vue版本:v2.5.17-beta。0
vue在数据更新后会自动触发视图的渲染工作,其依赖于数据驱动;在数据驱动的工作下,每一个vue的数据属性都被监听,并且在集触发时,派发事件,通知收集到的依赖,从而触发对应的操作,使工作就是其中的一个依赖,并且被每一个数据属性所收集,因此每一个数据属性改变后,都会触发渲染。
看一段代码
//来自mountComponent函数 updateComponent=function () { vm._update (vm._render(),保湿); }; 新观察家(vm, updateComponent,等待,{ :函数在(){ 如果(vm._isMounted) { callHook (vm, beforeUpdate); } } },真正的/* isRenderWatcher */);
updateComponent是更新组件的函数,内部调用vm._update,并且传参vm._render ();
-
<李> vm._render()返回了什么?看源码则得知返回了虚拟dom (VNode) 李>
<李> vm._update函数又做了什么事情?顾名思义,更新传入的vnode李>
<李>什么时候触发updateComponent函数?在任何vue的数据属性更改值都会触发李>
阅读_update函数得知,最终调用了vm.__patch__方法,最终找到为createPatchFunction方法的返回值
var补?createPatchFunction ({nodeOps: nodeOps模块:模块}); Vue.prototype。__patch__=inBrowser & # 63;补丁:无操作;>之前接下来重点看createPatchFunction的返回函数补丁。
如果新的vnode不存在,则注销旧的vnode
如果(isUndef (vnode)) { 如果(isDef (oldVnode)) {invokeDestroyHook (oldVnode);} 返回 }如果旧的vnode不存在,则创建新的vnode
如果(isUndef (oldVnode)) {//空挂载(可能为组件),创建新的根元素 isInitialPatch=true; createElm (vnode insertedVnodeQueue); }如果以上不成立,则新的vnode和oldVnode都存在。如果oldVnode不是真实的dom,则为虚拟dom节点,并且新老vnode相似,则进行diff算法
var isRealElement=isDef (oldVnode.nodeType); 如果(!isRealElement,,sameVnode (oldVnode vnode)) {//修补现有的根节点 patchVnode (oldVnode vnode、insertedVnodeQueue removeOnly); }如果新老vnode不同,则拿到oldVnode的父节点,辅助创建vnode的新节点
var oldElm=oldVnode.elm; var parentElm=nodeOps.parentNode (oldElm);//创建新节点 createElm ( vnode。 insertedVnodeQueue,//极其罕见的极端例子:不要插入是否在一个旧的元素//离开过渡。> 如果(oldVnode===vnode) { 返回 }如果vnode不是文本节点则有几种情况
如果(isDef (oldCh),,isDef (ch)) {//如果oldVnode和vnode的孩子都有值(组件层),并且不想等,则执行更新孩子流程 如果(oldCh !==ch) {updateChildren(榆树、oldCh ch、insertedVnodeQueue removeOnly);} }else if (isDef (ch)) {//如果vnode的孩子有值,如果当前dom有文本则清空,//并将oldVnode的dom作为父节点,创建新vnode的孩子节点 如果(isDef (oldVnode.text)) {nodeOps。setTextContent(榆树,”);} addVnodes(榆树,null, ch 0 ch.length - 1, insertedVnodeQueue); }else if (isDef (oldCh)) {//如果oldVnode存在的孩子,但是新的没有,则删除oldVnode的儿童的vnode removeVnodes (oldCh榆树oldCh 0。长度- 1); }else if (isDef (oldVnode.text)) {//如果oldVnode有文本信息,则将dom的文本清空 nodeOps。setTextContent(榆树,”); }如果vnode是文本节点,则当新老节点文本不同,将dom的文本更新成新vnode的文本
else if (oldVnode。文本!==vnode.text) { nodeOps。setTextContent(榆树,vnode.text); }patchVnode函数处理的情况梳理一下则为:
-
<李>如果新老vnode相同,不作处理李>
<李>如果新vnode是文本节点,并且新老文本不同,将dom更新为vnode的文本李>
<李>如果新老vnode都有孩子,表示他们是组件层,则调用updateChildren去做组件层更新李>
<李>如果新vnode是组件层,oldVnode不是,则将当前dom添加新vnode组件的子元素李>
<李>如果oldVnode是组件层,新vnode不是,则操作dom,将oldVnode包含的子元素删除李>
<李>如果新vnode是组件层,oldVnode是文本节点,则将dom的文本清空