关注公众号“放风筝的人”,回复“信息”获取500G信息(所有“军队”都有),更有专业交流群等你一起来。(哈哈)无论是Vue还是React,为了比较虚拟DOM节点的变化,做到最小更新,都使用了diff算法。本文就和老手一起看看diff算法。1、基本的Diff算法实现了虚拟DOM的最小更新。这句话虽然简短,却涉及到两个核心要素:虚拟DOM和最小更新。VirtualDOMVirtualDOM是指将真实的DOM树构造成js对象的形式,从而解决浏览器操作真实DOM的性能问题。比如下面这个DOM和虚拟DOM的映射关系,目的是通过最小更新Diff找到新旧虚拟DOM之间更新最小的部分,从而更新这部分对应的DOM。2.整个过程Diff算法真的很美。整个过程如下图所示:1.首先比较新旧节点是否是同一个节点(可以比较sel(选择器)和key(唯一标识)的值是否相同),如果不是同一个节点,则会被暴力删除(注意:先在旧节点的基础上插入新节点,再删除旧节点)。
2.如果是同一个节点,需要进一步比较
完全一样,不处理
新节点的内容是文本,直接替换即可
新节点有子节点,所以这时候你就得好好想想了:如果旧节点没有子元素,就清空旧节点,插入新节点的子元素;如果旧节点有子元素,需要按照上面的更新策略(记得更新策略,能吹几年,666666)。
三、实战只讲假手,下面会讲到diff算法的核心内容。3.1patch函数Diff算法的入口函数主要判断新旧节点是否为同一个节点,然后进行不同的逻辑处理。exportdefaultfunctionpatch(oldVnode,newVnode){//判断传入的第一个参数是DOM节点还是虚拟节点if(oldVnode.sel===''||oldVnode.sel===undefined){//传入的第一个参数是一个DOM节点,此时应该封装为虚拟节点。oldVnode=vnode(oldVnode.tagName.toLowerCase(),{},[],undefined,oldVnode);}//判断oldVnode和newVnode是否是同一个节点if(oldVnode.key===newVnode.key&&oldVnode.sel===newVnode.sel){//是同一个节点,然后细化比较patchVnode(oldVnode,新节点);}else{//不是同一个节点,暴力插入新的,删除旧的letnewVnodeElm=createElement(newVnode);//在旧节点之前插入新节点if(oldVnode.elm.parentNode&&newVnodeElm){oldVnode.elm.parentNode.insertBefore(newVnodeElm,oldVnode.elm);}//删除旧节点oldVnode.elm.parentNode.removeChild(oldVnode.elm);}}3.2patchVnode函数该函数主要负责细粒度比较。哪个分支,从而采用不同的处理逻辑。(思路清晰,算法太棒了)exportdefaultfunctionpatchVnode(oldVnode,newVnode){//判断新旧vnode是否是同一个对象if(oldVnode===newVnode){return;}//判断vnode是否有text属性if(newVnode.text!==undefined&&(newVnode.children===undefined||newVnode.children.length===0)){console.log('newvnode具有文本属性');if(newVnode.text!==oldVnode.text){oldVnode.elm.innerText=newVnode.text;}}else{//新vnode没有文本属性,但有子节点console.log('Thenewvnodehasnotextattribute');//判断老的没有孩子if(oldVnode.children!==undefined&&oldVnode.children.length>0){//老的有孩子,新的有孩子updateChildren(oldVnode.elm,oldVnode.children,newVnode.children);}else{//旧的没有孩子,新的有孩子//清除旧节点的内容oldVnode.elm.innerHTML='';//遍历新vnode的子节点,创建DOM,上树for(leti=0;i
