Vue diff patch 实现
cooljser 2022-01-11  vue
vue 虚拟 DOM 主要做了这三件事:
- 用 js 对象模拟 DOM 树;
- 比较两棵虚拟 DOM 树的差异;
- patch 算法,将虚拟 DOM 转换为真实 DOM。
// @ts-ignore
// @ts-nocheck
// 初始化 patch
function createElement(vnode) {
  let tag = vnode.tag; // 目标元素
  let attrs = vnode.attrs || {}; // 属性
  let children = vnode.children || []; // 子节点
  if (!tag) {
    return null;
  }
  // 1. 创建对象的 DOM
  let elem = document.createElement(tag);
  // 2. 添加属性
  for (const attrName in attrs) {
    if (Object.hasOwnProperty(attrName)) {
      elem.setAttribute(attrName, attrs[attrName]);
    }
  }
  // 3. 将子元素添加到目标元素
  children.forEach((childElement) => {
    elem.appendChild(createElement(childElement));
  });
  return elem;
}
// 更新阶段的 patch
function udpate(vnode, newVnode) {
  const children = vnode.children || [];
  const newChildren = newVnode.children || [];
  children.forEach((childElement, index) => {
    const newChildElement = newChildren[index];
    if (childElement.tag === newChildElement.tag) {
      // 递归更新
      update(childElement, newChildElement);
    } else {
      replace(childElement, newChildElement);
    }
  })
}
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
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
