vue源码复现
先进行语义解析各种vue命令生成模板语法树,再根据模板语法树使用createRender函数(render函数可使用自己定义的)创建render函数,在创建的同时使用闭包(函数柯里化)将模板语法树缓存起来,然后render函数结合data生成虚拟dom树,最后使用update方法根据diff规则将新的vnode替换旧的vnode(如果是相同id的新旧vnode比较,先遍历旧vnode所有属性,再遍历新vnode所有属性,然后进行属性补全)
vue2通过修改Array实例的__proto__重写了push等方法来实现数组的响应式
vue将this._data上的属性在做响应式处理时,在this上也放了一份,所以可以通过this也能访问到,其他的prop、methods也是同理
diff算法中自定义组件的更新和节点的更新判断逻辑不同
第一步先调用initdata对data里的每个属性对象做响应式处理在get方法中加上收集依赖(dep.depend)的方法,在set中添加派发更新(dep.notify)的方法,再调用mount解析template,触发渲染。这样的目的是将响应式和与渲染逻辑分开。
initdata中将数据做响应式处理,然后转交给initRender做渲染处理,通过52行使得每个响应式属性存储一份dep,每一份依赖又与该属性对应的的watch相关联,这样就使得渲染与属性分离
initRender做完抽象语法树转换后返回render函数,执行到16行的new Watch
进入到watcher后,又返回执行回调函数expOrFn,又返回至initRender中
最终调用的是update方法渲染虚拟dom
三个属性收集了三个dep依赖
每个dep中包含要更新的watcher实例,对应着当前vue实例
这三个属性对应的都是同一watcher实例
①在initRender过程中,也就是在解析template的过程中会访问数据,此时会触发属性的get方法,
②通过dep.depend进行依赖收集,将vue实例保存至watcher中通过dep这个桥梁与该响应式属性相关联
③每次修改该属性,则触发dep.notify通知该属性绑定的watcher(对应的vue实例)进行重新渲染
④若template中没有用到该响应式属性(在data中定义的变量),则该属性也不会绑定任何watcher,即使修改了该属性的值,也不会进行渲染