likes
comments
collection
share

《Vuejs设计与实现》8.9 更新子节点

作者站长头像
站长
· 阅读数 41

前面几章我们分别处理了vnode的属性,class名,事件。接下来我们看看,如何处理子节点。子节点就是我们vnode中的children,一般情况下,children会有三种值的类型:

  • null 表示没有子节点
  • String只有一个文本节点
  • 其他情况时,数组中会有具体的子节点,无论是文本节点还是其他vnode

子节点是null的时候

当子节点是null的时候,如果它发生改变,只会有三种情况:

null --> null //可忽略
null --> string
null --> [vnode,vnode]

其中第一种情况可以完全忽略,这种情况下我们无需执行任何操作。,这就意味着子节点只能变成文本节点或子节点数组。

当子节点由null --> string,很好处理,我们可以直接调用setElementText去赋值就可以了。

当子节点由null --> [vnode,vnode]时,稍微麻烦一点,我们需要去递归children,把子节点逐一挂载就可以了。

我大概写一下我自己理解的伪代码。

const patchChildren = (oldNode,newNode,container)=>{
    if(oldNode.children === null && newNode.children !== null){
        if(typeof newNode.children === 'string' ){
            setElementText(container,newNode.children)
        } else if(Array.isArray(newNode.children)){
            //这里是递归
            newNode.children.forEach(node=>patchChildren(null,node,newNode.el))
        }
    }

}

子节点是文本节点

当字节点是是文本节点,就会有三种情况:

string --> null 
string --> string
string --> [vnode,vnode]

当子节点由字符串变成字符串时,我们需要判断一下内容是否相等,如果相等也就无需更新了,因此我们可以这样去写

const patchChildren = (oldNode,newNode,container)=>{
    // 这里就过滤了两个同时为字符串且相等
    if(typeof oldNode.children === 'string' && oldNode.children !== newNode.children){
      if(newNode.children === null){
          setElementText(container,'')
      } else if(Array.isArray(newNode.children)){
         oldNode.children.forEach(node=>{
             patchChildren(oldNode.children,node,newNode.el)
         })
      } else {
          setElementText(container,newNode.children)
      }
    }
}

这个分支下,暂时也比较好理解,我们只需要排除字符串相等的情况,其他情况下根据newNode.children去更新就行了。

子节点是数组时

这个分支下就比较麻烦了,我们首先看看他的三种情况:

[vnode,vnode] --> null 
[vnode,vnode] --> string
[vnode,vnode] --> [vnode2,vnode2]

对于前两种情况,我们需要考虑把vnode卸载掉,然后重新插入节点。但是第三种情况很复杂,我之前也讲过,需要递归对比,主要指的就是第三种情况。

const patchChildren = (oldNode,newNode,container)=>{
    if(Array.isArray(oldNode.children)){
        if(newNode.children === null || typeof newNode.children==='string'){
            oldNode.children.forEach(node=>unmount(node))
            setElementText(container,newNode.children ?? '')
        } else {
         //这里就需要diff算法了
        }
    }
})

我理解的diff算法,其实是递归对比子节点的区别,并按最小更新量去更新,这个算法会在书里的第9章去讲,我现在也就不写了(因为我也不会)

转载自:https://juejin.cn/post/7137478132566589447
评论
请登录