vue数据绑定详解

转载 (原文地址) greenhand 随笔 JavaScript 165阅读 2019-02-27 13:43:58 举报

vm.$data结构如下

initData

其实这段代码主要做了两件事,一是将_data上面的数据代理到vm上,另一件事通过observe将所有数据变成observable。

observe

Vue实例的data数据中每个对象(包括vm.$data本身)都会有一个ob的属性作为标记,里面存放了该属性的观察器,也就是Observer的实例,防止重复绑定。

Observer

Observer的作用就是遍历对象的所有属性将其进行双向绑定。

Observer为数据加上响应式属性进行双向绑定。如果是对象则进行深度遍历,为每一个子对象都绑定上方法,如果是数组则为每一个成员都绑定上方法。所以如果数组的成员是对象,直接修改数组成员的属性时(直接this.array[0].xx=yy,而不是使用splice方法),也是会触发render的。详见vue array test

如果是修改一个数组的成员,该成员是一个对象,那只需要递归对数组的成员进行双向绑定即可。但这时候出现了一个问题,?如果我们进行pop、push等操作的时候,push进去的对象根本没有进行过双向绑定,更别说pop了,那么我们如何监听数组的这些变化呢? Vue.js提供的方法是重写push、pop、shift、unshift、splice、sort、reverse这七个数组方法。修改数组原型方法的代码可以参考observer/array.js以及observer/index.js。

从数组的原型新建一个Object.create(arrayProto)对象,通过修改此原型可以保证原生数组方法不被污染。如果当前浏览器支持proto这个属性的话就可以直接覆盖该属性则使数组对象具有了重写后的数组方法。如果没有该属性的浏览器,则必须通过遍历def所有需要重写的数组方法,这种方法效率较低,所以优先使用第一种。

在保证不污染不覆盖数组原生方法添加监听,主要做了两个操作,第一是通知所有注册的观察者进行响应式处理,第二是如果是添加成员的操作,需要对新成员进行observe。

但是修改了数组的原生方法以后我们还是没法像原生数组一样直接通过数组的下标或者设置length来修改数组,可以通过Vue.set以及splice方法。

Watcher

Watcher是一个观察者对象。依赖收集以后Watcher对象会被保存在Deps中,数据变动的时候会由Deps通知Watcher实例,然后由Watcher实例回调cb进行视图的更新。

vm._watcher,vm._watchers可以查看有哪些watcher

渲染template会对应一个watcher,vue实例初始化时,先创建相应的watcher对象并执行render函数(watch.getter会调用render函数),这样watcher对象就会获取模板中用到的data里的数据的值,从而data里的每一个数据就能收集到有哪些watcher依赖它,下次修改时就可以通知这些watcher来重新render。模板中未用到的data里的属性修改时,不会触发update,因为这些属性对应的dep的subs为空数组,没有watcher依赖它们

vm.$watch(expOrFn, callback)也是通过创建watcher实例来实现监控

Dep

其实Dep就是一个发布者,可以订阅多个观察者,依赖收集之后Deps中会存在一个或多个Watcher对象,在数据变更的时候通知所有的Watcher。

defineReactive

接下来是defineReactive。defineReactive的作用是通过Object.defineProperty为数据定义上getter\setter方法,进行依赖收集后闭包中的Deps会存放Watcher对象。触发setter改变数据的时候会通知Deps订阅者通知所有的Watcher观察者对象进行试图的更新。

评论 ( 0 )
最新评论
暂无评论

赶紧努力消灭 0 回复