likes
comments
collection
share

虚拟dom

作者站长头像
站长
· 阅读数 15

vue中的虚拟dom

简介

首先vue会把模板编译成render函数,运行render函数生成虚拟dom

虚拟dom通过 diff算法 对比差异 渲染不同的部分 然后更新视图

为什么会需要虚拟dom

在主流框架 Angular , Vue.js (1.0)React 中都有一个共同点,那就是它们都不知道哪些状态(state)变了。因此就需要进行比对,在React中使用的虚拟dom比对, Angular 中使用的是脏检查的流程

而在 Vue.js中使用的是变化侦测的方式,它在一定程度上知道具体哪些状态发生了变化,这样就可以通过更细粒度的绑定来更新视图。也就是说,在Vue.js中,当状态发生变化时,它在一定程度上知道哪些节点使用了这个状态,从而对这些节点进行更新操作,根本不需要比对

但是这样做的代价就是,粒度太细,每一个都有对应的 watcher 来观察状态变化,这样就会浪费一些内存开销,绑定的越多开销越大,如果这运用在一个大型项目中,那么他的开销无疑是非常大的

因此从 Vue.js 2.0 开始借鉴 React 中的虚拟DOM ,组件级别是一个watcher实例,就是说即便一个组件内有10个节点使用了某个状态,但其实也只有一个watcher在观察这个状态的变化。

什么是虚拟dom

虚拟DOM是通过状态生成一个虚拟节点树(vnode) ,然后使用虚拟节点树进行渲染。 在渲染之前,会使用新生成的虚拟节点树和上一次生成的虚拟节点树进行对比 (diff算法) ,只渲染不同的部分

虚拟节点树其实是由组件树建立起来的整个虚拟节点(Virtual Node,也经常简写为vnode)树

在Vue.js中,我们使用模板来描述状态DOM之间的映射关系。Vue.js通过编译将模板转换成渲染函数(render),执行渲染函数就可以得到一个虚拟节点树,使用这个虚拟节点树就可以渲染页面

模板编译成render函数

将模板编译成渲染函数可以分两个步骤,先将模板解析成AST(Abstract Syntax Tree,抽象语法树),然后再使用AST生成渲染函数。

但是由于静态节点不需要总是重新渲染,所以在生成AST之后、生成渲染函数之前这个阶段,需要做一个操作,那就是遍历一遍AST,给所有静态节点做一个标记,这样在虚拟DOM中更新节点时,如果发现节点有这个标记,就不会重新渲染它。所以,在大体逻辑上,模板编译分三部分内容:

  • 将模板解析为AST
  • 遍历AST标记静态节点
  • 使用AST生成渲染函数

虚拟dom做了什么

虚拟DOM在Vue.js中所做的事情其实并没有想象中那么复杂,它主要做了两件事。

  • 提供与真实DOM节点所对应的虚拟节点vnode。
  • 将虚拟节点vnode和旧虚拟节点oldVnode进行比对,然后更新视图。

对两个虚拟节点对比是虚拟dom 中最核心的算法 (diff),它可以判断出哪些节点发生了变化,从而只对发生了变化的节点进行更新操作

小结

虚拟DOM是将状态映射成视图的众多解决方案中的一种,它的运作原理是使用状态生成虚拟节点,然后使用虚拟节点渲染视图。

为什么会需要虚拟dom
框架设计

Vue 和 React 框架设计理念都是基于数据驱动的,当数据发生变化时 就要去更新视图,要想知道在页面众多元素中改动数据的元素 并根据改动后的数据去更新视图 是非常困难的

所以 Vue 和 React 中都会有一个 Render函数 或者类似于Render函数的功能,当数据变化时 全量生成Dom 元素 如果是直接操作 真实Dom 的话 是很昂贵的,就会严重拖累效率,所以就不生成真实的Dom,而是生成虚拟的Dom 当数据变化时就是 对象 和 对象 进行一个对比 ,这样就能知道哪些数据发生了改变 从而去操作改变的数据后的Dom元素

这也是一个 “妥协的结果”

跨平台

现阶段的框架他不仅仅能在浏览器里面使用,在小程序,移动端,或者桌面端也可以使用,但是真实Dom仅仅指的是在浏览器的环境下使用,因此他不能直接生成真实Dom ,所以选择生成一个在任何环境下都能被认识的虚拟Dom 最后根据不同的环境,使用虚拟Dom 去生成界面,从而实现跨平台的作用 --- 一套代码在多端运行