这篇文章不是原创,看了其他人的分析贴,记录下自己学到的。本篇主要记录一下vue内部流程,以及双向绑定原理。Vue的可爱之处在于他的双向绑定及Virtual DOM的思想。
vue内部流程
如图所示,实例化组件时,调用init方法,初始化事件,属性,data等。初始化data,是实现双向绑定的重要一步(后面再详细说)。挂载($mount)时,根据传入的模版解析编译成 render function。 再把render function 转成 Virtual DOM tree(虚拟DOM树)。数据更新时,Virtual DOM tree转成 真正的DOM之前,经历patch方法,计算那些更新的节点,更新相应的节点,生成DOM.每个步骤拆开的话如下:
init
组件实例化时,调用init(),初始化组件的生命周期相关属性,事件,props,data等等。vue双向绑定也在这个期间完成的(后面再细说)。
compile
组件$mount(挂载)时,根据传入的模版或者节点标识(id等)把组件模版编译(compile)成render function。 编译过程分三步:
- parse 解析模版中的指令,属性等数据,形成AST(抽象语法树),例如:
const element2 = {
type: 1,
tag: 'a',
attrsList: [{name: ":href", value: "url"}, {name: "target", value: "_blank"}],
attrsMap: {':href': 'url', 'target': '_blank'},
parent: element1,
children: []
};
- optimize 标记静态节点,更新视图时,根据diff算法计算更新的节点时,直接跳过静态节点,提高diff算法性能。
- generate 把AST 转成render function.
render
render function 转成 VNode, 生成Virtual DOM tree(虚拟DOM树).VNode其实是一个描述DO节节点的javascript对象,抽象真正的DOM节点.为什么需要Virtual DOM ? 因为DOM操作总是很慢,操作数据对象不仅快,还有跨平台的能力。VNode比如:
{
tag: 'div',
children: [
tag: 'a',
text: 'click me'
}
]
}
patch
数据更新时,patch方法是新的 Virtual DOM 树和旧 Virtual DOM 的diff算法,算出更新了哪些节点,更新对应的DOM节点。
双向绑定实现
vue的双向绑定是通过Object.definerProperty加发布订阅模式实现的。
object.defineProperty具体知识移步这里。重点是它的get和set方法,比如这个例子:
var obj = {};
var a;
Object.defineProperty(obj, 'a', {
get: function() {
console.log('get val');
return a;
},
set: function(newVal) {
console.log('set val:' + newVal);
a = newVal;
}
});
obj.a; // get val
obj.a = '111'; // set val: 111
vue的双向绑定原理就是,比如data.number ='123';每个组件用到number属性的时候,都会调object.defineProperty()的get函数,从而收集到依赖number属性的vue组件。每个组件实例话时都有一个watcher,就是订阅者。我们叫收集依赖的对象为Dep。
看下Dep对象
//依赖收集对象
class Dep {
constructor () {
this.subs = [];
}
//收集依赖
addSub (sub) {
this.subs.push(sub);
}
//发布变化
notify () {
this.subs.forEach((sub) => {
sub.update();
})
}
}
watcher对象
class Watcher {
constructor () {
Dep.target = this;
}
//更新视图
update () {
console.log("视图更新了哦");
}
}
初始化过后,Dep对象收集到依赖number属性的订阅者watcher1,watcher2(用到number属性的组件vue1,vue2),当number属性变化时,调用set函数,我们调用依赖收集对象的(发布者)update方法去发布更新,每个watcher(订阅者)都收到更新提示,更新视图。就是这个样子啦~其实不难。
对于那些,show me the code 的同学:demo代码
参考:
掘金[vue内部运行机制][4],、
源码讲解[vue2.0远吗解读][5]