我的理解是结合GitHub中一个MVVM.js的源码进行分析,该源码对vue的核心源码进行了分离。并且借助下面的流程图可以有助于理解。
当我们使用new MVVM({})方法时,第一个执行的函数应该是observer,它的作用是监视data中所有层次的属性,并且会创建一个与data中属性一一对应的dep对象。
data方法之后执行的函数是compile,他的作用是编译模板。它内部做了三件事。
- 第一,取出模板中所有子节点并存储在fragment对象中
- 第二,fragment会调用init方法对fragment对象中不同类型的节点进行编译解析 * 对表达式文本节点进行解析,解析分为:
* 对元素节点的指令属性进行解析
* 事件指令解析
* 一般指令解析 - 第三,将解析后的fragment添加到el中显示
compile方法执行后,也就是我们所理解的模板被解析完毕。理论上我们要展示页面了,所以这时就会通过updater方法来初始化页面。并且compile的同时会创建data中数据更新的订阅者(watcher),每一个watcher都会与表达式(事件指令除外)一一对应。
那么这里是如何对应的?其实就是因为compile的过程中会对不同类型的表达式进行类型判断,所以每一个watcher都被绑定了对应的数据更新函数。这里尤为重要,这就决定了下面所说的watcher和dep关联后如何触发正确的更新函数。
这里说一下核心源码所做的最后一个环节,watcher和dep的关联。其实是通过将watcher存储在dep的subs数组中。
- subs属性说明
* 当一个watcher被创建时, 内部会将当前watcher对象添加到对应的dep对象的subs中
* 当此data属性的值发生改变时, 所有subs中的watcher都会收到更新的通知, 从而最终更新对应的界面
此时当发生一个改变data的行为 this.name='B’时,observe中的set方法发现data中的属性改变,会去通知dep有data变化发生了,dep通知相关的watcher,从而去执行与相关watcher对应的updater函数,完成页面的更新。
在compile中有一个双向数据绑定需要特殊说明
1). 双向数据绑定是建立在单向数据绑定(model==>View)的基础之上的
2). 双向数据绑定的实现流程:
* 在解析v-model指令时, 给当前元素添加input监听
* 当input的value发生改变时, 将最新的值赋值给当前表达式所对应的data属性