虚拟 Dom

Monday, November 16, 2020

虚拟 Dom

  1. 什么是虚拟 dom

    dom 随时代发展的产物 功能多 =》 状态多 频繁操作 dom 复杂 dom 虽简单 不好维护

    主流框架声明式操作 dom 描述状态和 dom 的关系即可 我们只负责状态的维护 状态渲染成 dom 由框架完成

    状态 =》 js 的任意类型 以段落,表单按钮等元素呈现在页面

    状态 =》 dom = 渲染

    程序运行 状态不断改变 状态改变=》更新 dom

    最简单 不关心 直接删掉所有 dom 重新渲染生成一份

    优选 只更新相关的 只更新和状态相关的(Vue 属性绑定)

    虚拟 dom 比较旧的和新的

    vue1.0 利用绑定监听器 对所有属性监听更新 但实例太多 内存开销变大 不利于大型项目

    2.0 优化 一个组件绑定一个监听器,组件内所有属性都使用同一监听器,监听变化后使用虚拟 dom 进行循环比较,折中

    vue 编译模板 templete 生成 vnode 比较 vnode

  2. vnode

    看源码

    节点描述对象 缓存对比更新

    注释 文本 元素 组件

  3. patch

    vnode 之间的对比,不是暴力覆盖,对比是手段,不是目第,目第是修改 dom,渲染视图

    1. 创建新节点

    2. 删除废节点

    3. 修改更新节点

      只要能渲染出新 dom 即可

      1. 新增节点

        1. 没有 oldVnode 直接使用 vnode 创建元素并渲染
        2. vnode 和 oldvnode 完全不是一个节点时
      2. 删除节点

        1. vnode 和 oldvnode 完全不同,插入新节点,删除废弃旧节点
      3. 更新节点

        新增/删除 共同点 虚拟节点不同 =》 删除或新增

        新旧同一节点 比较 更新

        例如 文本不同 只更新文本即可

    4. 创建节点 /src/core/vdom/patch.js createElm

    5. 删除节点 removeNode

    6. 更新节点 patchVnode

      1. 静态节点(永远不变 没有 vmodel v-if 永远存在)
      2. 文本节点 先对比
      3. 元素节点
        1. 有子 判断旧 vnode 是否有子,有就递归对比更新,没有直接清空旧的,把新的子节点插入
        2. 不包含子 直接清空插入

    更新子节点

    1. 粗暴 两层循环对比 /src/core/vdom/patch.js updateChildren

      for (let i = 0; i < newChildren.length; i++) {
          const newChild = newChildren[i]
          for (let j = 0; j < oldChildren.length; j++) {
              const oldChild = oldChildren[j]
              if (newChild === oldChild) {
                  // ...
              }
          }
      }
      
      1. 创建

        循环找不到相同的,就要创建,问题是插入位置

        合适的位置是所有未处理节点之前,而并非所有已处理节点之后

      2. 删除

      3. 移动

        发现相同字节点 位置不同 需要移动

      4. 更新