其实没什么好讲、自己敲一遍就知道了。
本质就是对比新旧虚拟dom找出区别。
对比内容:节点、属性和子节点(子节点里有一样的三大元素:节点、属性和子节点)
对比结果:没有就增加、有且不相等就修改、旧vDOM有和新vDOM没有就删除和替换等。
复制粘贴到HTML上,即可实现功能
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Diff算法</title>
</head>
<body>
<div id="app"></div>
<script>
class Element {
constructor(type, props, children) {
this.type = type;
this.props = props;
this.children = children;
}
}
function createElement(type, props, children) {
return new Element(type, props, children);
}
const vDOM = createElement('ul',
{
class: 'list',
style: 'width: 300px; height: 300px; background-color: orange'
},
[
createElement('li',
{class: 'item', 'data-index': 0},
[
createElement('p', {class: 'text'}, ['第1个选项'])
]),
createElement('li',
{class: 'item', 'data-index': 1},
[
createElement('p', {class: 'text'}, [
createElement('span', {
class: 'text'
}, [
'第2个列表选项'
])
])
]
),
createElement('li',
{class: 'item', 'data-index': 2},
['第3个列表选项']
)
]
);
let vDOM2 = createElement('ul',
{
class: 'list-wrap',
style:'width: 300px; height: 300px; background-color: orange'
},
[
createElement('li',
{class: 'item', 'data-index':0 },
[
createElement('p', {class:'title'},['特殊选项'])
]),
createElement('li',
{class: 'item', 'data-index':1 },
[
createElement('p', {class:'text'},[
'第二选项'
])
]
),
createElement('li',
{class: 'item', 'data-index':2 },
['第333个列表选项12']
)
]
);
let patches = {};
let vnIndex = 0;
function diff(value, newValue) {
let index = 0;
vNodeWalk(value, newValue, index);
return patches;
}
function vNodeWalk(oldNode, newNode, index) {
let vnPatch = [];
if(!newNode){
vnPatch.push({
type: 'REMOVE',
index,
})
} else if(typeof oldNode ==='string' && typeof newNode === 'string'){
if(oldNode !== newNode){
vnPatch.push({
type: 'TEXT',
text: newNode
})
}
} else if (oldNode.type === newNode.type) {
const attrPatch = attrsWalk(oldNode.props, newNode.props)
if (Object.keys(attrPatch).length > 0){
vnPatch.push({
type: 'ATTR',
attrs: attrPatch
})
}
childrenWalk(oldNode.children, newNode.children);
} else {
vnPatch.push({
type: 'REPLACE',
newNode
})
}
if (vnPatch.length > 0){
patches[index] = vnPatch;
}
}
function childrenWalk(oldChild, newChild){
oldChild.map((child, index) => {
vNodeWalk(child, newChild[index], ++vnIndex);
})
}
function attrsWalk(oldAttrs, newAttrs) {
let attrPatch = {};
Object.keys(oldAttrs).forEach(key => {
if(oldAttrs[key] !== newAttrs[key]){
attrPatch[key] = newAttrs[key];
}
});
Object.keys(newAttrs).forEach(key => {
if(!oldAttrs.hasOwnProperty(key)){
attrPatch[key] = newAttrs[key]
}
});
return attrPatch
}
const result = diff(vDOM,vDOM2);
console.log(result);
</script>
</body>
</html>