# 深入响应式原理
defineProperty
当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data
选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty
(opens new window) 把这些 property 全部转为 getter/setter
由于Object.defineProperty
是 ES5 中一个无法 shim 的特性,这也就是 Vue 不支持 IE8 以及更低版本浏览器的原因。
watcher
每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。
# 保证数据响应式
- 对于对象
property 必须在 data
对象上存在才能让 Vue 将它转换为响应式的
var vm = new Vue({
data: {
a: 1
}
});
// `vm.a` 是响应式的
vm.b = 2;
// `vm.b` 是非响应式的
// 代替 `Object.assign(this.someObject, { a: 1, b: 2 })`
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 });
- 对于数组
Vue 重写了数组的操作方法,调用这些方式时,可以进行消息通知,从而更新
var vm = new Vue({
data: {
items: ["a", "b", "c"]
}
});
vm.items[1] = "x"; // 不是响应性的
vm.items.length = 2; // 不是响应性的
vm.$set(vm.items, indexOfItem, newValue); //是响应式的
vm.items.splice(newLength); //是响应式的
# 异步更新队列
Vue 在更新 DOM 时是异步执行的,只要侦听到数据变化,Vue 将开启一个队列,并缓冲在同一循环中发生的所有数据变更。
当然如果同一个 watcher 被多次触发,只会被推入到队列中一次。然后在下一个事件循环“tick"中,Vue 刷新队列并执行实际工作。 所以不用担心 Watch 出现死循环的问题。
为了在数据变化之后等待 Vue 完成更新 DOM,可以在数据变化之后立即使用Vue.nextTick(callback)
.