# 手写 Dom dff
vnode.js
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);
}
module.exports = createElement;
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
- 这就是一个虚拟 dom╮(╯▽╰)╭
- 其实就是把一些属性挂载
index.js
import createElement from "./vnode.js";
import domDiff from "./diff.js";
let vDmo1 = createElement(
"ul",
{
className: "list"
},
[
createElement("li", { className: "item" }, ["1"]),
createElement("li", { className: "item" }, ["2"]),
createElement("li", { className: "item" }, ["3"])
]
);
let vDmo2 = createElement(
"ul",
{
className: "new-list"
},
[
createElement("li", { className: "item" }, ["a"]),
createElement("li", { className: "item" }, ["2"]),
createElement("li", { className: "item" }, ["b"])
]
);
console.log(domDiff(vDmo1, vDmo2));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
- 把虚拟 dom 方法和 diff 方法都引进来
- 创建两个虚拟 dom 进行比较
utils.js
export default {
isString(type) {
return typeof type === "string";
}
};
1
2
3
4
5
2
3
4
5
- 一个工具类,用来判断是否是字符串
diff.js
import utils from "./utils.js";
let patches = [];
function domDiff(oldDom, newDom) {
walk(oldDom, newDom, index);
return patches;
}
function walk(oldDom, newDom, index) {
let patch = [];
// 如果newDom不存在则意味着是删除
if (!newDom) {
patch.push({
type: "REMOVE",
index
});
}
// 对比文本
else if (utils.isString(oldDom) && utils.isString(newDom)) {
if (oldDom !== newDom) {
patch.push({
type: "TEXT",
text: newDom
});
}
} else if (oldDom.type === newDom.type) {
let attr = diffAttr(oldDom.props, newDom.props);
if (Object.keys(attr).length) {
patch.push({
type: "ATTR",
attr
});
}
diffChildren(oldDom.children, newDom.children);
} else {
pathch.push({
type: "REPLACE",
newDom
});
}
if (patch.length) {
patches[index] = patch;
}
}
function diffAttr(oldProps, newProps) {
let attr = {};
for (let key in oldProps) {
if (oldProps[key] !== newProps[key]) {
attr[key] = newProps[key];
}
}
for (let key in newProps) {
if (!oldProps.hasOwnProperty(key)) {
attr[key] = newProps[key];
}
}
return attr;
}
function diffChildren(oldChildren, newChildren) {
oldChildren.forEach((child, i) => {
walk(child, newChildren[i], ++index);
});
}
export default domDiff;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
diff.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>简单的dom diff</title>
</head>
<body>
<script src="./code/index.js" type="module"></script>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12