You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
functionupdateChildren(parentElm,oldCh,newCh,insertedVnodeQueue,removeOnly){letoldStartIdx=0letnewStartIdx=0letoldEndIdx=oldCh.length-1letoldStartVnode=oldCh[0]letoldEndVnode=oldCh[oldEndIdx]letnewEndIdx=newCh.length-1letnewStartVnode=newCh[0]letnewEndVnode=newCh[newEndIdx]letoldKeyToIdx,idxInOld,vnodeToMove,refElm// removeOnly is a special flag used only by <transition-group>// to ensure removed elements stay in correct relative positions// during leaving transitionsconstcanMove=!removeOnlyif(process.env.NODE_ENV!=='production'){checkDuplicateKeys(newCh)}//当新节点和旧节点都没有遍历完成while(oldStartIdx<=oldEndIdx&&newStartIdx<=newEndIdx){if(isUndef(oldStartVnode)){oldStartVnode=oldCh[++oldStartIdx]// Vnode has been moved left}elseif(isUndef(oldEndVnode)){oldEndVnode=oldCh[--oldEndIdx]}elseif(sameVnode(oldStartVnode,newStartVnode)){//oldStartVnode和newStartVnode,相同sameVnode//直接将该VNode节点进行patchVnodepatchVnode(oldStartVnode,newStartVnode,insertedVnodeQueue,newCh,newStartIdx)//获取下一组开始节点oldStartVnode=oldCh[++oldStartIdx]newStartVnode=newCh[++newStartIdx]}elseif(sameVnode(oldEndVnode,newEndVnode)){//直接将该VNode节点进行patchVnodepatchVnode(oldEndVnode,newEndVnode,insertedVnodeQueue,newCh,newEndIdx)oldEndVnode=oldCh[--oldEndIdx]newEndVnode=newCh[--newEndIdx]}elseif(sameVnode(oldStartVnode,newEndVnode)){// Vnode moved right//直接将该VNode节点进行patchVnodepatchVnode(oldStartVnode,newEndVnode,insertedVnodeQueue,newCh,newEndIdx)//获取下一组结束节点canMove&&nodeOps.insertBefore(parentElm,oldStartVnode.elm,nodeOps.nextSibling(oldEndVnode.elm))oldStartVnode=oldCh[++oldStartIdx]newEndVnode=newCh[--newEndIdx]}elseif(sameVnode(oldEndVnode,newStartVnode)){// Vnode moved left//oldStarVnode和newStartVnode相同//进行patchVnode,把oldStartVnode移动到最后patchVnode(oldEndVnode,newStartVnode,insertedVnodeQueue,newCh,newStartIdx)canMove&&nodeOps.insertBefore(parentElm,oldEndVnode.elm,oldStartVnode.elm)//移动游标,获取下一组节点oldEndVnode=oldCh[--oldEndIdx]newStartVnode=newCh[++newStartIdx]}else{//以上四种清空都不满足//newStartVnode 依次和旧的节点比较//从新的节点开头获取一个,去老节点中查找相同节点//先找新开始节点的key和老节点相同的索引,如果没找到再通过sameVnode找if(isUndef(oldKeyToIdx))oldKeyToIdx=createKeyToOldIdx(oldCh,oldStartIdx,oldEndIdx)idxInOld=isDef(newStartVnode.key)
? oldKeyToIdx[newStartVnode.key]
: findIdxInOld(newStartVnode,oldCh,oldStartIdx,oldEndIdx)//如果没找到if(isUndef(idxInOld)){// New element//创建节点并插入到最前面createElm(newStartVnode,insertedVnodeQueue,parentElm,oldStartVnode.elm,false,newCh,newStartIdx)}else{//获取要移动的老节点vnodeToMove=oldCh[idxInOld]//如果使用 newStartVnode 找到相同的老节点if(sameVnode(vnodeToMove,newStartVnode)){//执行patchVnode,并且将找到的节点移动到最前面patchVnode(vnodeToMove,newStartVnode,insertedVnodeQueue,newCh,newStartIdx)oldCh[idxInOld]=undefinedcanMove&&nodeOps.insertBefore(parentElm,vnodeToMove.elm,oldStartVnode.elm)}else{//如果key相同,但是是不同的元素,创建新元素// same key but different element. treat as new elementcreateElm(newStartVnode,insertedVnodeQueue,parentElm,oldStartVnode.elm,false,newCh,newStartIdx)}}newStartVnode=newCh[++newStartIdx]}}//当结束时oldStartIdx > oldEndIdx,旧节点遍历完,但是新节点还没有if(oldStartIdx>oldEndIdx){//说明新节点比老节点多,把剩下的新节点插入到老的节点后面refElm=isUndef(newCh[newEndIdx+1]) ? null : newCh[newEndIdx+1].elmaddVnodes(parentElm,refElm,newCh,newStartIdx,newEndIdx,insertedVnodeQueue)}elseif(newStartIdx>newEndIdx){//当结束时 newStartIdx > newEndIdx,新节点遍历完,但是旧节点还没有removeVnodes(oldCh,oldStartIdx,oldEndIdx)}}
概念
代码演示
h函数
vm.$createElement(tag, data, children, normalizeChildren)
,返回了一个虚拟节点VNodeVNode
虚拟DOM创建的整体过程
createElement
src\core\vdom\create-element.js
createElement() 函数,用来创建虚拟节点 (VNode),我们的 render 函数中的参数 h,就是createElement()
h函数,render()中调用,用户传递的或者编译生成的 render 函数,这个时候传递了 createElement,通过代码演示
_update
src\core\instance\lifecycle.js
vnode处理过程
判断是否有prevVnode
运用
__patch__
方法创建$el__patch__
src\core\vdom\patch.js
运用__patch__方法创建$el
createElm
src\core\vdom\patch.js
patchVnode
src\core\vdom\patch.js
setTextContent
修改文本updateChildren
设置key
**作用:**在v-for中,为每个节点设置key可以使它跟踪每个节点的身份。进行比较时,会基于key的变化重新排列元素顺序,从而重用和重新排序现有元素,并且移除key不存在的元素,方便让Vnode在diff过程中找到对应的节点,然后复用。
**好处:**减少DOM操作,减少diff和渲染所需事件,提高性能
The text was updated successfully, but these errors were encountered: