给真实dom打补丁

71 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第8天,点击查看活动详情

这是根据上一篇虚拟节点的差异化分析 得到的差异化数组,来对真实的dom打补丁的,我们需要定义个函数,把把原始dom和补丁包传进去作处理

index.js

dopatch(realdom,h) // 真实dom h为补丁包

我们新建了一个dopatch.js文件 一步一步看

let oldpatch = {}; // 这个是保存原始补丁的
let realindex =0; // 补丁是有编号的所以真实节点也需要有编号 
// 新声明了两个属性

写了dopatch方法

function dopatch(realdom,patch) {
    oldpatch = patch
    realDomwalk(realdom) // 这方法很重要 这是递归真实dom用的 
}

realDomwalk函数

// 真实dom的遍历也是深度优先遍历
function realDomwalk(realdom) { 
    // 拿到应对应的节点补丁没有·就是空
    const rnPatch = oldpatch[realindex++] // 这个是拿到相对应真实dom索引的补丁
    // 当前节点可能会有children
    const childNodes = realdom.childNodes; // 这个拿到的是类十足
    [...childNodes].map(item=>{
        // item是子节点
        realDomwalk(item) // 相当于真实节点的递归
    })
    // 判断rnPatch是否存在 如果存在就开始打补丁
    if (rnPatch) { 
       patchAction(realdom,rnPatch)  // 这个函数才是真的的打补丁函数 当前节点的补丁
    }
}

patchAction这个方法 也是比较重要的这是我们用来做打补丁的方法

function patchAction(realdom,patch) {
   // patch应该是补丁包样子 0: [
    //     {
    //         type: "ATTR",
    //         attrs: {
    //            class: 'llll'
    //        }
    //     }
    // ],
    // 是个数组
    patch.forEach(item=>{
        // 这里需要判断一下属性
        if (item.type==ATTR) { // 如果是attr我们需要为真实dom替换属性
            for (let k in item.attrs) {
                let value = item.attrs[k]
                // 判断value是否存在 如果存在我们就进行打补丁
                if (value) {
                    setAtts(realdom,k,value)
                } else {
                    realdom.removeAttribute(k)
                }
            }
   
        } else if(item.type==TEXT) { // 如果是文本节点 直接给节点赋值就可以了
            realdom.textContent = item.text
        } else if (item.type==REPLACE) { 
           // 如果是替换节点 我们需要先删除节点 在之前的父节点添加节点
           // 需要判断一下新的节点是不是符合我们Element构造出来的
           // 如果是Element构造出来 需要变为真实dom
           // 如果不是就是文本节点
           let newNode =(item.newDom instanceof Element)?render(item.newDom): document.createTextNode(item.newDom)
           console.log(item)
           realdom.parentNode.replaceChild(newNode,realdom)
        } else if (item.type==REMOVE) { // 直接删除节点
            realdom.parentNode.removeChild(realdom)
        }
    })
}

代码里的注释其实就是这个这个方法里最重要的,我们写的这个只做个4中操作,其实只是提供了一个大概的思路,复杂操作的思路其实差不多,如果大家想要这个源码的话可以给我留言,感谢阅读