学习十六、Vue 中的虚拟 dom

1、什么是虚拟 DOM

- 虚拟 DOM(Virtual DOM)是使用 JavaScript 对象描述真实 DOM

- Vue.js 中的虚拟 DOM 借鉴 Snabbdom,并添加了 Vue.js 的特性。

  例如: 指令和组件机制

2、 为什么要使用虚拟 DOM

- 避免直接操作 DOM,提高开发效率

- 作为一个中间层可以跨平台

- 虚拟 DOM 不一定可以提高性能

  - 首次渲染的时候会增加开销

  - 复杂视图情况下提升渲染性能

3、Vue 虚拟 dom 完整的渲染过程

  • new Vue()
  • this._init()
  • vm.$mount()
    • src/platforms/web/entry-runtime-with-compiler.js
    • 如果没有传递 render,把模板编译成 render 函数
    • compileToFunction() 生成 render() 渲染函数
    • option.render = render
  • vm.$mount
    • src/platforms/web/runtime/index.js
    • mountComponent()
  • mountComponent(this, el)
    • src/core/instance/lifecycle.js
    • 判断是否含有 render 选项,如果没有但是传入了模板,并且当前是开发环境,会发送警告
    • 触发 beforeMount
    • 定义 updateComponent
      • vm._update(vm._render(), ...)
      • vm._render() 渲染,渲染虚拟DOM
      • vm._update() 更新,将虚拟DOM转移成真实 DOM
    • 创建 Watcher 实例
      • updateComponent 传递
      • 调用 get() 方法
    • 触发 mounted
    • return vm
  • watcher.get()
    • 创建完 watcher 回调用一次 get
    • 调用 updateComponent()
    • 调用 vm._render() 创建 Vnode
      • 调用 render.call(vm._renderProxy, vm.$createElement)
      • 实例化时 Vue 传入的 render()
      • 或者编译 template 生成的 render()
      • 返回 VNode
    • 调用 vm._update(vnode, ...)
      • 调用 vm.patch(vm.$el, vnode) 挂载真实 DOM
      • 记录 vm.$el
  • updateComponent()
  • vm._render()
    • vnode = render.call(vm._renderProxy, vm.$createElement)
    • vm.$createElement()
      • h函数,用户设置的 render 函数中调用
      • createElement(vm, a, b, c, s, true)
    • vm._c()
      • h 函数,模板编译的 render 函数中调用
      • createElement(vm, a, b, c, d, true)
    • _createElement()
      • vnode = new VNode(config.parePlatformTagname(tag), data, children, undefined, undefined, context)
      • vm._render() 结束,返回 VNode
  • vm._update()
    • 负责把虚拟 DOM,渲染成真实 DOM
    • 首次执行 vm.patch(vm.$el, vnode, hydrating, false)
    • 数据更新 vm.patch(prevVnode, vnode)
  • vm.patch()
    • runtime/index.js 中挂载 Vue.prototype.patch
    • runtime/patch.js 的 patch 函数
    • 设置 modules 和 nodeOps
    • 调用 createPacthFunction() 函数 返回 patch 函数
  • patch()
    • vdom/patch.js 中的 createPatchFunction 返回 patch 函数
    • 挂载 cbs 节点的属性/事件/样式操作的钩子函数
    • 判断第一个参数是真实 DOM 还是虚拟 DOM。首次加载,第一个参数就是真实 DOM,转换成 VNode,调用 createElm
    • 如果是数据更新的时候,新旧节点是 sameVnode 执行 patchVnode,就是Diff
    • 删除旧节点
  • createElement(vnode, insrtedVnodeQueue)
    • 把虚拟节点,转换成真实 DOM,并插入到 DOM 树
    • 把虚拟节点的 children,转换为真实 DOM,并插入到 DOM 树
  • patchVnode
    • 对比新旧Vnode,以及新旧VNode的子节点更新差异
    • 如果新旧VNode都有子节点并且子节点不同的话,会调用updateChildren 对比子节点的差异
  • updateChildren
    • 从头和尾开始依次找到相同的子节点进行比较 patchVnode,总共有四种比较方式
    • 在老节点的子节点中查找 newStartVnode,并进行处理
    • 如果新节点比老节点多,把新增的子节点插入到 DOM 中
    • 如果老节点比新节点多,把多余的老节点删除

猜你喜欢

转载自blog.csdn.net/qq_40289624/article/details/109491077