虚拟 DOM
虚拟 DOM 是一个抽象的 DOM 树副本,通常是一个纯 JavaScript 对象(本质上就是一个普通的 JS 对象),用于描述视图的页面结构。
可以在 mounted 中使用 this._vnode 看到该组件生成的虚拟 dom。
每一个组件都有一个 render 函数,每个 render 函数都会通过 h 函数创建并 返回一个 虚拟 DOM 树,所以每个组件都对应一个虚拟 DOM 树。
为什么需要虚拟 DOM?
在 vue 中,渲染视图会调用 render 函数,这种渲染不仅发生在组件创建时,同时发生在视图依赖的数据更新时。如果在渲染时,直接使用真实 dom,由于真实 dom 的创建、更新、插入等操作会带来大量的性能损耗,极大降低渲染效率。虚拟 dom 主要解决渲染效率问题。
所以一个是创建一个个的普通对象(
let obj = {}),一个是创建一个个的 html 元素(let obj = document.createElement('div')),明显创建对象的效率更高。
虚拟 dom 转为 真实 dom?
一个组价实例首次被渲染时,先生成虚拟 dom 树,然后根据虚拟dom 树创建真实dom,并把真实 dom 挂载到页面上,每个虚拟 dom 都会对应一个真实 dom。
一个组件受响应书数据变化的影响,需要重新渲染时,会重新调用render 函数,创建一个新的虚拟 dom 树,然后新树和旧树进行对比,找到差异(需要更新的地方),使用新树,抛弃旧树,更新需要更新的真实 dom。
template 模板与虚拟 dom 的关系
vue 框架(主文件夹)中有一个 compile 模块(子文件夹),它主要负责将模板转换为 render 函数,而 render 函数调用后将得到虚拟 dom。
编译的过程分两步:
- 将模板(template,实际上转换后就是一个字符串)字符串转换成为 AST
- 将 AST 转换为 render 函数
AST类似于虚拟DOM,但仅仅是类似:
astexplorer.net/ 可用该网站查看代码对应的抽象语法树 AST
如果使用传统的引入方式(script)或 vue-cli 的配置(vue.config.js)中开启了runtimeCompiler:true,则编译时间发生在组件第一次加载时,这称之为运行时编译。
如果是在 vue-cli 的默认配置下,编译发生在打包时,这称之为模板预编译。这是运行时不需要编译,效率提高。
其实,不只是运行 build 的时候会打包,运行 npm run serve 等的时候也会打包,只是不形成打包文件。
编译是一个极其耗费性能的操作,预编译可以有效的提高运行时的性能,而且,由于运行的时候已不需要编译,vue-cli在打包时会排除掉vue中的compile模块,以减少打包体积。
模板的存在,仅仅是为了让开发人员更加方便的书写界面代码。
vue最终运行的时候,最终需要的是render函数,而不是模板,因此,模板中的各种语法,在虚拟dom中都是不存在的,它们都会变成虚拟dom的相关配置。
虚拟 DOM 的优势:
-
性能优化:虚拟 DOM 可以减少直接操作实际 DOM 的次数,从而提高页面渲染性能。通过批量处理 DOM 更新操作,可以减少浏览器的重排和重绘。
-
简化开发:虚拟 DOM 提供了一种更抽象的方式来操作页面结构,使得前端开发更加容易理解和维护。它将组件化开发推向了前台,有助于构建模块化的应用。
-
更好的可维护性:虚拟 DOM 可以让开发者专注于数据和组件的状态,而不必担心手动管理实际 DOM 的状态。这提高了代码的可维护性。