preact系列之diffElementNodes

218 阅读1分钟

阅读须知

  • 文章参考的preact版本是10.5.13
  • 文章会省略大部分逻辑,比如hydrating,context,isSvg等。所以如果有大佬点进来需谨慎。
  • 简略版本代码

diffElementNodes概览

  • 作用:对参数dom进行各种属性比较赋值 或者 新建dom返回。
  • 如果oldVnode上没有dom会根据对应type去新建
  • 处理props和children
    • 对于文本节点直接修改data从而实现dom的复用修改,nodeType===null
    • 非文本节点:对比props,对比子节点
function diffElementNodes(
    dom,
    newVNode,
    oldVNode,
    commitQueue,
) {
    let oldProps = oldVNode.props;
    let newProps = newVNode.props;
    let nodeType = newVNode.type;
    let i = 0;
    
    // 没有dom就去创建节点
    // 处理props和children
   
   return dom;
}

创建节点

  • 没有nodeType就默认创建文本节点,有的就根据类型创建对应节点
// 如果oldVnode上没有dom会根据对应type去新建
if (dom == null) {
    if (nodeType === null) {
        return document.createTextNode(newProps);
    }

    dom = document.createElement(
        nodeType,
        newProps.is && newProps
    );
    excessDomChildren = null;
}

props和children的处理

  • 文本节点,props的直接替换。
  • 非文本节点
    • newProps与oldProps比较。

文本节点

// 在children.js 对比文本节点的不同会先创建新的文本节点的vNode,type===null 
// 对于文本节点直接修改data从而实现dom的复用修改
if (nodeType === null) {
    if (oldProps !== newProps && dom.data !== newProps) {
        dom.data = newProps;
    }
}

非文本节点

else {
    excessDomChildren = excessDomChildren && EMPTY_ARR.slice.call(dom.childNodes);
    oldProps = oldVNode.props || EMPTY_OBJ;
    
    diffProps(dom, newProps, oldProps, isSvg, isHydrating);
    
    
    i = newVNode.props.children;
    diffChildren(
        dom,
        Array.isArray(i) ? i : [i],
        newVNode,
        oldVNode,
        commitQueue,
        dom.firstChild,  // dom是oldVNode._dom  旧节点的第一个子节点继续做比较
    );
    
    if (excessDomChildren != null) {
        for (i = excessDomChildren.length; i--; ) {
            if (excessDomChildren[i] != null) removeNode(excessDomChildren[i]);
        }
    }
    
}