持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第5天,点击查看活动详情
这个新旧虚拟节点的差异化分析,我们只分析最基本和最简单的变更,不会做节点复用和新增节点
这是新老节点图片,就是一个示意图
我们需要把新旧dom的差异化做成一个数组,数组的样子大家可以看下,我们最后用代码对比出来的也和这个值差不多
差异对比大概之后大概就是这个样子,patch对象的0、2、6就是虚拟化之后dom的顺序 大家示意图也可以看出来
let patch = {
0: [
{
type: "ATTR",
attr: "list-warp"
}
],
2: [
{
type: "ATTR",
attr: 'title'
}
],
6: [
{
type: "REMOVE",
index: 6
},
],
7: [
{
type: 'REPLACE',
newNode: newNode
}
]
}
可以新建一个diff.js文件,去专门做差异化检验问题,也就是diff,vue是双端指针校验,我们这里做的比较简单,只是从头开始循环校验校验,没有vue的复杂,可以就是当diff的思路 diff 的方法
function domDiff(oldDom,newDom) {
// 在这里我们还要去对比dom的 children 会用到递归所以我们要写成一个函数方便使用
let index = 0; // 这个是专门walkdom这个方法使用的
walkdom(oldDom,newDom,index) // 这里主要调用的就是这个
return patchs
}
walkdom方法核心 我们在这里做的异化校验和赋值
function walkdom(oldDom, newDom,index) { // 主要对比的是节点,只关心当前节点
let patch = []; // 只存放当前节点的差异
// 首先判断在新的当前节点还在不在, 如果不在了就直接remove了
if (!newDom) {
patch.push({
type: REMOVE,
index: index
})
} else if(typeof oldDom== 'string'&&typeof newDom=="string") { // 新老节点都是文本节点情况
if (oldDom!=newDom) {
patch.push({
type: TEXT,
text: newDom
})
}
} else if (oldDom.type==newDom.type) { // 如果标签相等 我们需要去对比属性
// 判断属性这个还是比较复杂的
let attrpatch = attrwalk(oldDom.props,newDom.props);// 属性补丁
// 判断attrpatch是否是空对象
if(Object.keys(attrpatch).length>0) {
// 如果不为0 需放在patch缓存里
patch.push({
type: ATTR,
attrs: attrpatch
})
}
// 如果标签是一样的有子属性的 需要遍历子属性
childrenwalk(oldDom.children,newDom.children)
} else { // 节点变了
patch.push({
type: REPLACE,
newDom
})
}
// 判断patch是否是空的 空的代表没有差异化
if (patch.length>0) {
patchs[index] = patch
}
}
attrwalk 方法主要是比对属性的
function attrwalk(oldprops,newprops) {
let attrPatch = {}
// 循环老的属性比较新节点的属性
for (let key in oldprops) {
if (newprops[key]!=oldprops[key]) { // 对比新老节点属性
attrPatch[key] = newprops[key] // 修改属性
}
}
// 是否有新加属性 循环新的属性 如果老的属性没有 就是新的了
for (let key in newprops) {
if(!oldprops.hasOwnProperty(key)) {
attrPatch[key] = newprops[key] // 新增
}
}
// 返回属性的补丁
return attrPatch
}
childrenwalk主要是递归子元素用的
// 节点子标签
function childrenwalk(oldchildren,newchildren) {
if (!oldchildren) return
oldchildren.map((c,idx)=>{
walkdom(c,newchildren[idx],++vnindex) // 全局index主要作用是 全部标记
})
}
看我我打印出来的数据
后面还会做把差异化,打补丁到真实dom上