先读一段对话娱乐一下~
我:——你在干嘛?
男票(Android客户端):——吃屎
我:——emmmm,懂了(他在读Android源码···)
好吧~我也要直播吃屎了······接下来就是我看完vue/src/core/observer之后的总结以及源码分析~看源码不仅是看实现原理,也是看大牛的编码风格,以及为日后接触别的框架源码打基础,今天我主要聊的就是Vue的双向数据绑定~
Vue在双向数据绑定这块做的事情就是:
通过Observer(数据监听器)对data中的属性做监听,为data中的每一个属性提供Dep(消息订阅器),Dep内部维护了一个数组subs用来添加Watcher(订阅者)
把template编译成一段document fragment,然后解析其中的Directive(指令),得到每一个Directive所依赖的数据项和update方法,并为每一个与数据绑定的节点生成一个Watcher,Watcher会将自己添加到对应属性的Dep中
通过Watcher将Observer和template的Directive连接起来。template通过一次render(渲染)操作触发所有被render所依赖(保证只有视图中需要被用到的data才会触发getter)的data中的数据的getter进行依赖收集(通过Watcher订阅在对应数据的Observer的Dep的subs中);当数据发生变化的时候,就会触发数据的setter,setter会触发Observer的Dep调用notify方法来通知对应的Watcher进行通知组件重新渲染的update方法,进而触发Directive的update方法来更新视图
从vue如何给data添加Observer开始,回顾一下vue实例创建的生命周期,其中,vm.initData方法处理data选项。
initData:
1 | // 源码目录:src/core/instance/state.js |
这段代码的重点其实在proxy和observer。可以看到proxy的功能就是遍历data的key,把data上的属性代理到vm实例上。observer的功能就是对data作监听了。
proxy:
1 | 源码目录:src/core/instance/state.js |
observe:
1 | 源码目录:src/core/observer/index.js |
Observer类:
1 | 源码目录:src/core/observer/index.js |
defineReactive:
1 | // 源码目录:src/core/observer/index.js |
Dep:
1 | // 源码目录:src/core/observer/dep.js |
依赖收集:Dep类是一个简单的观察者模式的实现。当对data上的对象进行修改值的时候会触发它的setter,那么取值则会触发它的getter。所以,将Watcher实例赋值给全局的Dep.target,然后触发render操作,只有被被Dep.target标记过的data中的数据才会被getter收集到Dep的subs中;在对data中的数据进行修改的时候,触发setter的时候,Dep会调用subs中的Watcher实例的update方法进行渲染。