组件如何渲染
初次渲染过程
- 解析模版为render函数(或在开发环境已经完成,vue-loader)
- 触发响应式,监听 data属性gettersetter
- 执行 render函数,生成vnode,patch(elem, vnode)
更新过程
- 修改 data, 触发setter(此前在getter中已被监听)
- 重新执行 render函数,生成newVnode
- patch(vnode, newVnode)
异步渲染 $nextTick
- 汇总 data的修改,一次性更新视图
- 减少 DOM 操作次数,提高性能
虚拟 DOM 和 diff
- vdom 是实现 vue 和 React 的重要基石
- diff 算法是vdom 中最核心、最关键的部分
用JS模拟DOM结构
1
2
3
4
5
6
<div id="div1" class="container">
    <p>vdoom</p>
    <ul style="font-size:20px">
        <li>a</li>
    </ul>
</div>
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
{
    tag: 'div',
    props: {
        className: 'container', 
        id: 'div1'
    },
    children: [
        {
            tag: 'p',
            children 'vdom'
        },
        {
            tag: 'ul',
            props: { style: 'font-size: 20px' },
            children: [
                {
                    tag: 'li',
                    children: 'a'
                }
                // ....
            ]
        }
    ]
}
下面用js将dom字符转化为DOM结构:
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
function parseHTMLToVNode(htmlString) {
  // 创建一个临时的DOM元素
  const tempDiv = document.createElement('div');
  tempDiv.innerHTML = htmlString.trim();
  // 递归解析节点
  function parseNode(node) {
    if (node.nodeType === 3) { // 文本节点
      return node.nodeValue;
    }
    if (node.nodeType === 1) { // 元素节点
      const vnode = {
        tag: node.tagName.toLowerCase(),
        attrs: {},
        children: []
      };
      // 解析属性
      for (let attr of node.attributes) {
        vnode.attrs[attr.name] = attr.value;
      }
      // 递归解析子节点
      for (let childNode of node.childNodes) {
        vnode.children.push(parseNode(childNode));
      }
      return vnode;
    }
  }
  return parseNode(tempDiv.firstChild);
}
// 测试
const htmlString = '<div id="text" class="content">这是一段内容<span style="color: red">我是标会的内容</span>不知道是什么内容<p>1234567</p>哈哈哈哈</div>';
const vdom = parseHTMLToVNode(htmlString);
console.log(vdom); 
// {"tag":"div","attrs":{"id":"text","class":"content"},"children":["这是一段内容",{"tag":"span","attrs":{"style":"color: red"},"children":["我是标会的内容"]},"不知道是什么内容",{"tag":"p","attrs":{},"children":["1234567"]},"哈哈哈哈"]}
通过 snabbdom学习 vdom
- 简洁强大的vdom库,易学易用(https://github.com/snabbdom/snabbdom)
- vue 参考它实现的 vdom 和 diff
Vue2 Vue3 React 三者 diff 算法有何区别?
- vue2- 双端比较
- vue3- 最长递增子序列
- react- 仅右移
