数据双向绑定原理(数据劫持原理)
- 深度遍历实例 data 中的所有属性,
- 通过
Object.defineProperty()
方法将它们全部变成getter
、setter
以此进行数据劫持 - 每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染
注意:
- Vue 会在初始化实例时实现 data=>setter 和 getter 的转化,因此只有 data 中的数据才会是响应式的
Object.defineProperty()
方法是是 ES5 中一个无法shim的特性,这也就是 Vue不支持 IE8 以及更低版本浏览器的原因。
Object.defineProperty()
在一个对象上定义新属性,或者修改对象的现有属性并返回这个对象
obj
要定义属性的对象。
prop
要定义或修改的属性的名称或Symbol
。
descriptor
要定义或修改的属性描述符。
被传递给函数的对象。
set
和get
方法
1 | const object1 = {}; |
set 和 get 是其内置方法,可直接设置 writable 属性为 true,来允许改写对象属性
1 | const object1 = {}; |
数组更新检测
对于 data 中的数组中的属性不是响应式的,它们没有被监听,因此无法通过直接赋值触发重绘
1 | vm.arr[0] = 'newName'; //不是响应性的 |
Vue.set() API
Vue.set( target, propertyName/index, value )
- 参数:
{Object | Array} target
{string | number} propertyName/index
{any} value
用法:
向响应式对象中添加一个 property,并确保这个新 property 同样是响应式的,且触发视图更新。它必须用于向响应式对象上添加新 property,因为 Vue 无法探测普通的新增 property (比如this.myObject.newProperty = 'hi'
)
- 注意对象不能是 Vue 实例,或者 Vue 实例的根数据对象。
变更方法
Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。这些被包裹过的方法包括:
push()``向数组的末尾添加一个或多个元素,并返回新的长度
shift()``数组中删除第一个元素,并返回该元素的值
pop()``删除最后一个元素,并返回该元素的值
unshift()``将一个或多个元素添加到数组的开头,并返回该数组的新长度
splice()
删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容sort()
reverse()
你可以打开控制台,然后对前面例子的items
数组尝试调用变更方法。比如example1.items.push({ message: 'Baz' })
。
替换数组
变更方法,顾名思义,会变更调用了这些方法的原始数组。相比之下,也有非变更方法,例如filter()
、concat()
和slice()
。它们不会变更原始数组,而总是返回一个新数组。当使用非变更方法时,可以用新数组替换旧数组:
1 | example1.items = example1.items.filter(function (item) { |
你可能认为这将导致 Vue 丢弃现有 DOM 并重新渲染整个列表。幸运的是,事实并非如此。Vue 为了使得 DOM 元素得到最大范围的重用而实现了一些智能的启发式方法,所以用一个含有相同元素的数组去替换原来的数组是非常高效的操作。
评论