vue最独特的特性之一,是其非侵入式的响应式系统。数据模型仅仅是普通的Javascript对象,当你修改它们时,视图会更新,这使得状态管理非常简单直接。
如何追踪变化
当你把一个普通的Javascript对象传给Vue实例的data选项,Vue将遍历此对象所有的属性,并使用Object.defineProperty把这些属性全部转为getter/setter.Object.defineProperty是ES5中一个无法shim的特性。所以Vue不支持IE8以及更低版本浏览器。
这些getter/setter对用户来说是不可见的,但是在内部它们让Vue追踪依赖,在属性被访问和修改时通知变化,这里需要注意的问题是浏览器控制台在打印数据对象时getter/setter的格式化并不同,所以你可能需要安装vue-devtools来获取更加友好的检查接口。
每个组件实例都有相应的watcher实例对象,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的setter被调用时,会通知watcher重新计算,从而致使它关键的组件得以更新。

检测变化的注意事项
受现代Javascript的限制(Object.observe已经被废弃),Vue不能检测到对象属性的添加或删除。由于Vue会在初始化实例时对属性执行getter/setter转化过程,所以属性必须在data对象上存在才能让Vue转换它,这样才能让它是响应的。
var vm = new Vue({
data:{
a:1
}
})
//vm.a是响应的
vm.b = 2;
//vm.b是非响应的
Vue不允许在已经创建的实例上动态添加新的根级响应式属性,但是它可以使用Vue.set(object,key,value)方法将响应属性添加到嵌套的对象上:
Vue.set(vm.someObject,'b',2);
//或者下面这么写
this.$set(this.someObject,'b',2)
有时你想向一个已有对象添加多个属性,例如使用Object.assign()或_.extent()方法来添加属性。但是这样添加到对象上的新属性不会触发更新。在这种情况下可以创建一个新的对象,让它包含原对象的属性和新属性。
this.someObject = Object.assign({},this.someObject,{a:1,b:2})
声明响应式属性
由于Vue不允许动态添加根级响应式属性,所以你必须在初始化实例前声明根级响应式属性,哪怕只是一个空值:
如果你未在data选项中声明,Vue将警告你渲染函数正在视图访问的属性不存在。
这样的限制在背后是有其技术原因的,它消除了在依赖项跟踪系统中的一类边界情况,也使Vue实例在类型检查系统的帮助下运行的更高效。而且在代码可维护性方面也有一点重要的考虑,data对象就像组件状态的概要,提前声明所有的响应式属性,可以让组件代码在以后重新阅读或其他开发人员阅读时更易于被理解。
异步更新队列
Vue异步执行DOM操作。只要观察到数据变化,Vue将开启一个队列,并缓存在同一事件循环中发生的所有数据改变。如果同一个watcher被多次触发,只会 被推人到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和DOM操作上非常重要。然后,在下一个的事件循环‘tick’中,Vue刷新队列并执行实际工作,Vue在内部尝试对异步队列使用原生的Promise.then和MessageChanner,如果执行环境不支持,会采用SetTimeout(fn,0)代替。
多数情况我们不需要关心这个过程,但是如果你想在 DOM 状态更新后做点什么,这就可能会有些棘手。虽然 Vue.js 通常鼓励开发人员沿着“数据驱动”的方式思考,避免直接接触 DOM,但是有时我们确实要这么做。为了在数据变化之后等待 Vue 完成更新 DOM ,可以在数据变化之后立即使用 Vue.nextTick(callback) 。这样回调函数在 DOM 更新完成后就会调用。
网友评论