手写一个简单的React--diff算法

export function diff(dom, vnode, container) {
    const ret = diffNode(dom, vnode)
    if (container) {
        container.appendChild(ret)
    }
    return ret
}
function diffNode(dom, vnode) {
    let out = dom
    if (vnode === undefined || vnode === null) return
    if (typeof vnode === 'number') vnode = String(vnode)
    //文本节点
    if (typeof vnode === 'string') {
        if (dom && dom.nodeType === 3) {
            if (dom.textContent !== vnode) {
                //更新文本内容
                dom.textContent = vnode
            }
        } else {
            out = document.createTextNode(vnode)
            if (dom && dom.parentNode) {
                dom.parentNode.replaceNode(out, dom)
            }
        }
        return out
    }
    //非文本DOM节点
    if (!dom) {
        out = document.createElement(vnode.tag)
    }
    //比较子节点
    if (vnode.childrens && vnode.childrens.length > 0 || (out.childNodes && out.childNodes.length > 0)) {
        diffChildren(out, vnode.childrens)
    }
    diffAttribute(out, vnode)
    return out
}
function diffChildren(out, vchildren) {
    const domChildren = dom.childNodes
    const children = []
    const keyed = {}
    //将有key的节点(用对象保存)和没有key的节点(用数组保存)分开
    if (domChildren.length > 0) {
        [...domChildren].forEach(item => {
            const key = item.key
            if (key) {
                keyed[key] = item
            } else {
                children.push(item)
            }
        })
    }
    if (vchildren && vchildren.length > 0) {
        let min = 0
        let childrenLen = children.length
        [...vchildren].forEach((vchild, i) => {
            const key = vchild.key
            let child
            if (key) {
                if (keyed[key]) {
                    child = keyed[key]
                    keyed[key] = undefined
                } else if (childrenLen > min) {
                    for (let j = min; j < childrenLen; j++) {
                        let c = children[j]
                        if (c) {
                            child = c
                            children[j] = undefined
                            if (j === childrenLen - 1) childrenLen--;
                            if (j === min) min++
                            break;
                        }
                    }
                }
                child = diffNode(child, vchild)
                const f = domChildren[i]
                if (child && child !== dom && child !== f) {
                    if (!f) {
                        dom.appendChild(child)
                    } else if (child === f.nextSibling) {
                        removeNode(f)
                    } else {
                        dom.insertBefore(child, f)
                    }
                }
            }
        })
    }
}
function diffAttribute(dom, vnode) {
    //dom 是原有的节点对象  vnode虚拟dom
    const oldAttrs = {}
    const domAttrs = dom.attributes
    [...domAttrs].forEach(item => {
        oldAttrs[item.name] = item.value
    })
    for (let key in newAttrs) {
        if (!(key in oldAttrs)) {
            setAttribute(dom, key, undefined) // 设置属性
        }
    }
    //更新
    for (let key in newAttrs) {
        if (oldAttrs[key] !== newAttrs[key]) {
            setAttribute(dom, key, newAttrs[key])
        }
    }
}
全部评论

相关推荐

点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务