Vue的响应式原理
2017-05-15 23:09
411 查看
下面的是一张来自Vue官网的图片:
从上面的图可以看出,对于数据Data来说,它里面的getter与setter是对于外部是不可见的,但是在内部完全可以使用它们,在内部,通过Vue进行追踪依赖,当属性被修改或者访问时通知变化。每个组件的实例都会有相应的watcher实例对象,它会在组件渲染的过程中将属性记为依赖,之后当依赖项的
Vue不允许在已经创建的实例上动态添加新的根级响应式属性,然而它可以使用
也可以使用
有时你想向已有的对象添加一些属性,例如使用
如果在data选项中未声明
这样的限制,消除了在依赖项跟踪系统的一类边界情况,也使Vue实例在类型检查系统的帮助下运行的更高效,而且在代码可维护性方面也有所考虑,
例如,当你设置了
在组件内使用
参考:https://cn.vuejs.org/v2/guide/reactivity.html
如何追踪变化??
当把一个普通的JavaScript对象传递给Vue实例的data选项,Vue将遍历这个对象的所有属性,并且利用Object.defineProperty这些属性全部转换为getter/setter,当然由于兼容性问题,所以Vue不支持IE8及更低版本的浏览器
从上面的图可以看出,对于数据Data来说,它里面的getter与setter是对于外部是不可见的,但是在内部完全可以使用它们,在内部,通过Vue进行追踪依赖,当属性被修改或者访问时通知变化。每个组件的实例都会有相应的watcher实例对象,它会在组件渲染的过程中将属性记为依赖,之后当依赖项的
setter被调用时,会通知
watcher重新计算,从而让和它相关联的组件得以更新
变化的检测问题
受现代浏览器的限制(以及废弃的Object.observe),Vue不能检测到对象属性的添加或者删除,由于Vue在初始的时候就会对属性实行getter/setter转换过程,所以属性必须存在于
data对象时才能让Vue转换它,这样它才是响应的,这段话的意思等同于下面的代码:
//初始化之前写在data中的可以让Vue转换它,所以a是响应的 var v = new Vue({ data : { a : 1 } }); //初始化之后添加的属性b是非响应的 v.b = 2;
Vue不允许在已经创建的实例上动态添加新的根级响应式属性,然而它可以使用
Vue.set(Object, key, value)方法将响应属性添加到嵌套的对象上
Vue.set(vm.someObject, 'b', 2)
也可以使用
v.$set实例方法,这也是全局
Vue.set方法的别名:
this.$set(this.someObject,'b',2)
有时你想向已有的对象添加一些属性,例如使用
Object.assign()或
_.extend()方法来添加属性,但是,添加到对象上的新属性不会触发更新,在这中情况下,可以创建一个新的对象,让它包含原对象的属性和新的属性:
// 代替 `Object.assign(this.someObject, { a: 1, b: 2 })` this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })
声明响应式属性
由于Vue不允许动态添加根级响应式属性,所以必选在初始化实例前生命根级响应式属性,可以是空值var vm = new Vue({ data: { // 声明 message 为一个空值字符串 message: '' }, template: '<div>{{ message }}</div>' }) // 之后设置 `message` vm.message = 'Hello!'
如果在data选项中未声明
message,Vue将警告渲染函数试图访问的属性不存在
这样的限制,消除了在依赖项跟踪系统的一类边界情况,也使Vue实例在类型检查系统的帮助下运行的更高效,而且在代码可维护性方面也有所考虑,
data对象就像组件状态的概要,提前声明所有的响应式属性,可以让组件代码在以后阅读或开发人员阅读时更易于被理解
异步更新队列
Vue异步执行DOM更新,只要观察到数据变化,Vue将开启一个队列,并缓冲在同一事件循环中发生的数据改变,如果同一个watcher被多次触发,只会一次推入到队列中。这种缓冲时去除重复数据对于避免不必要的计算和DOM操作上非常重要,然后,在下一个的事件循环”tick”中,Vue刷新队列并执行实际(已去重的)工作。Vue在内部尝试对异步队列使用原生的promise.then和
MutationObserver,如果执行环境不支持,会采用
setTimeout(fn, 0)代替
例如,当你设置了
vm.someData = 'new value',该组件不会立即重新渲染,当刷新队列时,组件会在事件循环队列清空的下一个”tick”更新,多数情况下我们不需要关心这个过程,但是如果你想在DOM状态更新后做点什么,这就可能会有点困难,为了使得数据变化之后等待Vue完成更新DOM,可以在数据变化之后立即使用
Vue.nextTick(callback)这样回掉函数在DOM更新后就会调用。
<div id="example">{{message}}</div> <script type="text/javascript"> var vm = new Vue({ el: '#example', data: { message: '123' } }); vm.message = 'new message' // 更改数据 console.log(vm.$el.textContent); //123 Vue.nextTick(function () { alert(2323); console.log(vm.$el.textContent); //new message }); </script>
在组件内使用
vm.$nextTick()实例方法特别方便,因为它不需要全局Vue,并且回掉函数中的
this将自动绑定到当前的Vue实例上
Vue.component('my-component', { template: '<span> {{message}}</span>', data : function() { return { message: 'not update' } }, methods : { updateMessage : function() { this.message = 'update'; console.log(this.$el.textContent); //'not update' this.$nextTick(function() { console.log(this.$el.textContent); //'update' }); } } });
参考:https://cn.vuejs.org/v2/guide/reactivity.html
相关文章推荐
- Vue 响应式原理
- Vue 响应式原理
- 浅谈Vue 数据响应式原理
- Vue响应式原理深入解析及注意事项
- Vue.js每天必学之内部响应式原理探究
- vue 响应式原理
- vue 深入响应式原理
- Vue.2.0.5-深入响应式原理
- vue 深入响应式原理 注意事项
- 饿了么项目---7、深度响应式原理与Vue.$nextTick()的使用(2)
- Vue.js响应式原理
- Vue实现双向绑定的原理以及响应式数据的方法
- 学习 vue 源码 -- 响应式原理
- vue 响应式原理
- Vue.js 进阶(1) -- 响应式原理
- vue笔记-----深入响应式原理
- Vue.js内部响应式原理探究
- vue源码--响应式设计原理
- 我是怎么明白vue和ng1的响应式原理的
- Vue 源码解析:深入响应式原理