前言
虽然工作中一直使用Vue作为基础库,但是对于其实现机理仅限于道听途说,这样对长期的技术发展很不利。所以最近攻读了其源码的一部分,先把双向数据绑定这一块的内容给整理一下,也算是一种学习的反刍。
本篇文章的Vue源码版本为v2.2.0开发版。
Vue源码的整体架构无非是初始化Vue对象,挂载数据data/props等,在不同的时期触发不同的事件钩子,如created() / mounted() / update()等,后面专门整理各个模块的文章。这里先讲双向数据绑定的部分,也是最主要的部分。
设计思想:观察者模式
Vue的双向数据绑定的设计思想为观察者模式,为了方便,下文中将被观察的对象称为观察者,将观察者对象触发更新的称为订阅者。主要涉及到的概念有:
1、Dep对象:Dependency依赖的简写,包含有三个主要属性id, subs, target和四个主要函数addSub, removeSub, depend, notify,是观察者的依赖集合,负责在数据发生改变时,使用notify()触发保存在subs下的订阅列表,依次更新数据和DOM。
2、Observer对象:即观察者,包含两个主要属性value, dep。做法是使用getter/setter方法覆盖默认的取值和赋值操作,将对象封装为响应式对象,每一次调用时更新依赖列表,更新值时触发订阅者。绑定在对象的__ob__原型链属性上。
源码实战解析
有过Vue开发基础的应该都了解其怎么初始化一个Vue对象:
new Vue({ el: '#container', data: { count: 100 }, ...});
那么我们就从这个count说起,看它是怎么完成双向数据绑定的。
下面的代码片段中英文注释为尤雨溪所写,中文注释为我所写,英文注释更能代表开发者的清晰思路。
首先从全局的初始化函数调用:initMixin(Vue$3);
,这里的Vue$3对象就是全局的Vue对象,在此之前已经挂载了Vue的各种基本数据和函数。这个函数体就是初始化我们上面声明Vue语句的过程化逻辑,取主体代码来看:
// 这里的options就是上面声明Vue对象的json对象Vue.prototype._init = function (options) { ... var vm = this; ... initLifecycle(vm); initEvents(vm); initRender(vm); callHook(vm, 'beforeCreate'); // 这里就是我们接下来要跟进的初始化Vue参数 initState(vm); initInjections(vm); callHook(vm, 'created'); ... };
新闻热点
疑难解答
图片精选