这篇文章不是原创,看了其余人的分析贴,记录下本身学到的。本篇主要记录一下vue内部流程,以及双向绑定原理。Vue的可爱之处在于他的双向绑定及Virtual DOM的思想。javascript
如图所示,实例化组件时,调用init方法,初始化事件,属性,data等。初始化data,是实现双向绑定的重要一步(后面再详细说)。挂载($mount)时,根据传入的模版解析编译成 render function。 再把render function 转成 Virtual DOM tree(虚拟DOM树)。数据更新时,Virtual DOM tree转成 真正的DOM以前,经历patch方法,计算那些更新的节点,更新相应的节点,生成DOM.每一个步骤拆开的话以下:vue
组件实例化时,调用init(),初始化组件的生命周期相关属性,事件,props,data等等。vue双向绑定也在这个期间完成的(后面再细说)。java
组件$mount(挂载)时,根据传入的模版或者节点标识(id等)把组件模版编译(compile)成render function。 编译过程分三步:git
const element2 = { type: 1, tag: 'a', attrsList: [{name: ":href", value: "url"}, {name: "target", value: "_blank"}], attrsMap: {':href': 'url', 'target': '_blank'}, parent: element1, children: [] };
render function 转成 VNode, 生成Virtual DOM tree(虚拟DOM树).VNode实际上是一个描述DO节节点的javascript对象,抽象真正的DOM节点.为何须要Virtual DOM ? 由于DOM操做老是很慢,操做数据对象不只快,还有跨平台的能力。VNode好比:github
{ tag: 'div', children: [ tag: 'a', text: 'click me' } ] }
数据更新时,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对象this
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代码url
参考:
掘金[vue内部运行机制][4],、 源码讲解[vue2.0远吗解读][5]