Repository navigation
Expand file tree
/
Copy pathpatch.js
More file actions
111 lines (100 loc) · 3.1 KB
/
Copy pathpatch.js
File metadata and controls
111 lines (100 loc) · 3.1 KB
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// 定义新旧节点差异的情况
var REPLACE = 0;
var REORDER = 1;
var PROPS = 2;
var TEXT = 3;
function patch(node, patches) {
var walker = {index: 0};
dfsWalk(node, walker, patches);
}
// 深度遍历DOM树节点
function dfsWalk(node, walker, patches) {
var currentPatches = patches[walker.index];
var len = node.childNodes
? node.childNodes.length
: 0;
for(var i = 0; i < len; i++) {
var child = node.childNodes[i];
walker.index++;
dfsWalk(child, walker, patches);
}
if(currentPatches) {
applyPatches(node, currentPatches);
}
}
function applyPatches(node, currentPatches) {
currentPatches.forEach((currentPatch) => {
switch(currentPatche.type) {
case REPLACE:
var newNode = (typeof currentPatch.node === 'string')
? document.createTextNode(currentPatch.node)
: currentPatch.node.render();
break;
case REORDER:
reorderChildren(node, currentPatch.moves);
break;
case PROPS:
setProps(node, currentPatch.props);
break;
case TEXT:
if(node.textContent) {
node.textContent = currentPatch.content;
} else {
// 兼容ie
node.nodeValue = currentPatch.content;
}
break;
default:
throw new Error('Unknow patch type' + currentPatch.type);
}
});
}
// 设置属性
function setProps(node, props) {
for(var key in props) {
if(props[key] === void 666) {
node.removeAttribute(key);
} else {
var value = props[key];
node.setAttribute(key, value);
}
}
}
// DOM重排序
function reorderChildren(node, moves) {
var staticNodeList = [...node.childNodes];
var maps = {};
staticNodeList.forEach((node) => {
if(node.nodeType === 1) {
var key = node.getAttribute('key');
if(key) {
maps[key] = node;
}
}
});
moves.forEach((move) => {
var index = move.index;
if(move.type === 0) {
// 移除标签
if(staticNodeList[index] === node.childNodes[index]) {
// 为了下一步插入,要删除对应位置的tags,
node.removeChild(node.childNodes[index]);
}
staticNodeList.splice(index, 1);
} else if(move.type === 1) {
// 插入新元素
var insertNode = maps[move.item.key]
? maps[move.item.key].cloneNode(true) // 重用元素
: (typeof move.item === 'object')
? move.item.render()
: document.createTextNode(move.item);
staticNodeList.splice(index, 0, insertNode);
node.insertBefore(insertNode, node.childNodes[index] || null);
}
});
}
patch.REPLACE = REPLACE;
patch.REORDER = REORDER;
patch.PROPS = PROPS;
patch.TEXT = TEXT;
module.exports = patch;