一文带你了解vue之虚拟dom

简介: 在面试的过程中,可能也会被问到对虚拟dom的理解,像这种面试题是比较宽泛的,面试官想知道你到底知道多少?既然是`理解`,那就只能是知无不言言无不尽,尽量组织下语言多说点,这样才显得专业素养比较高,接下来,我来谈谈自己的理解,切记不要去背,一定要理解之后,用自己的语言来描述出来。

在面试的过程中,可能也会被问到对虚拟dom的理解,像这种面试题是比较宽泛的,面试官想知道你到底知道多少?既然是理解,那就只能是知无不言言无不尽,尽量组织下语言多说点,这样才显得专业素养比较高,接下来,我来谈谈自己的理解,切记不要去背,一定要理解之后,用自己的语言来描述出来。

我们可以从以下四个方面来回答:

🌟 什么是虚拟dom

虚拟dom本质上就是一个普通的JS对象,用来描述视图上应该有哪些界面结构,并不生成界面。我们可以在生命周期mounted阶段打印一下this._vnode,如下:

描述了标签为div有哪些属性、以及有哪些子元素等等,它通过普通的js对象这种形式来描述页面上应该有哪些东西,但并不会生成界面。

image.png

在vue中,每个组件都有一个render函数,每一个render函数都会返回一个虚拟dom数,这也就意味着每个组件都对应一棵虚拟DOM树。

image.png

🌼 为什么需要虚拟dom

这个主要是由vue框架结构所决定的,在vue中,渲染视图会调用render函数,这种渲染不仅发生在组件创建时,而且还会发生在依赖的数据更新的时候。如果在渲染时,直接使用真实DOM,由于真实DOM的创建、更新、插入等操作会带来大量的性能消耗,从而会极大的降低渲染效率。

示例:对比创建js对象和创建真实dom对象进行用时对比

<script>
      var times = 10000000;//次数为1000万次
      //js对象
      console.time(`js object`);
      for (var i = 0; i < times; i++) {
        var obj = {};
      }
      console.timeEnd("js object");
      //真实dom对象
      console.time(`dom object`);
      for (var i = 0; i < times; i++) {
        var obj = document.createElement("div");
      }
      console.timeEnd("dom object");
</script>

运行结果

image.png

从结果看,js对象用时150ms,而真实dom用时将近7s了,这个还不算插入到页面中导致的重绘重排时间,非常恐怖!

因此,vue在渲染时,使用虚拟dom来代替真实dom,主要为解决渲染效率的问题。那光有虚拟dom也不能够啊,那页面咋显示呢?总不能是无字天书吧!接下来就是第三个方面了

🌴 虚拟dom是如何转换为真实dom的

在一个组件实例第一次被渲染的时候,它会先生成虚拟dom树,然后根据虚拟dom树创建真实dom,最后会把真实的dom挂载到页面中合适的位置,所以说,创建真实的dom这一步是少不了的,只能说尽量的少创建,如果说页面只需要渲染一次,后面的数据变化都不重新渲染页面,这时vue的效率跟直接操作dom效率相比其实是更加低的,因为它比直接操作dom还多一个步骤:创建虚拟dom。第一次vue渲染效率是不高的,但是后续就不一样了。

如果一个组件受到响应式数据变化的影响,需要重新渲染时,它仍然会重新调用render函数,创建一个新的虚拟dom树,这时会用新虚拟dom树(newVnode)和旧虚拟dom树(oldVnode)进行对比,通过比对,vue会找到最小更新量,然后更新必要的虚拟dom节点,最后,这些更新过的虚拟节点会去修改它们对应的真实dom。这样一来就保证了对真实dom的操作达到了最小的改动。

image.png

比对过程其实是用到了一个算法,叫patch,它可以判断出哪些节点发生了变化,从而只对发生变化的虚拟dom节点进行更新,关于patch我会专门出一篇文章谈谈自己的看法。

👋 模板和虚拟dom的关系

vue框架中有一个compile模块,它主要负责将模板转换为render函数,而render函数调用后得到虚拟dom。

编译过程分为两步:

  1. 将模板字符串转换为AST(Abstract Syntax Tree,抽象语法树)
  2. 将AST转换为render函数
  • 如果使用传统的引入方式(使用script标签引入vue.js),编译时间发生在组件第一次加载时,被称为运行时编译
  • 如果是在vue-cli默认配置下,编译发生在打时,被称为模板预编译

编译是一个极其耗费性能的操作,预编译可以有效的提高运行时的性能,而且,由于运行时已经不需要编译,vue-cli在打包时会排除掉vue中的compile模块,这样可以减少打包体积。

模板的存在,仅仅只是为了我们更加方便的书写界面代码,vue最终运行的时候,最终需要的是render函数,而不是模板,这里要注意的是vue它是不认识模板的,模板是vue-cli预编译所需要的,它最终会将模板编译成render函数提供给vue正常运行。因此模板中的各种语法,在虚拟dom中都是不存在的,它们都会变成虚拟dom的配置。

😊 好了, 以上就是我的分享,大家对于虚拟dom还有其它理解的话可以在评论区讨论鸭~

记得点赞 👍 支持一下哦~ 😘

相关文章
|
1天前
|
存储 JavaScript 前端开发
【Vue】绝了!这生命周期流程真...
【Vue】绝了!这生命周期流程真...
|
1天前
|
JavaScript 索引
【vue】框架搭建
【vue】框架搭建
6 1
|
1天前
|
JavaScript 前端开发 容器
< 每日小技巧: 基于Vue状态的过渡动画 - Transition 和 TransitionGroup>
Vue 的 `Transition` 和 `TransitionGroup` 是用于状态变化过渡和动画的组件。`Transition` 适用于单一元素或组件的进入和离开动画,而 `TransitionGroup` 用于 v-for 列表元素的增删改动画,支持 CSS 过渡和 JS 钩子。
< 每日小技巧: 基于Vue状态的过渡动画 - Transition 和 TransitionGroup>
|
1天前
|
JavaScript
【vue】setInterval的嵌套实例
【vue】setInterval的嵌套实例
5 1
|
1天前
|
JavaScript 前端开发 安全
【Vue】内置指令真的很常用!
【Vue】内置指令真的很常用!
|
1天前
|
JavaScript
【Vue】过滤器Filters
【Vue】过滤器Filters
|
1天前
|
存储 JavaScript
Vue的状态管理:Vuex的使用和最佳实践
【4月更文挑战第24天】Vue状态管理库Vuex用于集中管理组件状态,包括State(全局状态)、Getters(计算属性)、Mutations(同步状态变更)和Actions(异步操作)。Vuex还支持Modules,用于拆分大型状态树。使用Vuex时,需安装并创建Store,定义状态、getter、mutation和action,然后在Vue实例中注入Store。遵循最佳实践,如保持状态树简洁、使用常量定义Mutation类型、避免直接修改状态、在Actions中处理异步操作、合理划分Modules,以及利用Vuex提供的插件和工具,能提升Vue应用的稳定性和可维护性。
|
1天前
|
资源调度 JavaScript 前端开发
Vue的路由管理:VueRouter的配置和使用
【4月更文挑战第24天】VueRouter是Vue.js的官方路由管理器,用于在单页面应用中管理URL路径与组件的映射。通过安装并引入VueRouter,设置路由规则和创建router实例,可以实现不同路径下显示不同组件。主要组件包括:`&lt;router-link&gt;`用于创建导航链接,`&lt;router-view&gt;`负责渲染当前路由对应的组件。此外,VueRouter还支持编程式导航和各种高级特性,如嵌套路由、路由参数和守卫,以应对复杂路由场景。
|
1天前
|
JavaScript 前端开发 开发者
Vue的响应式原理:深入探索Vue的响应式系统与依赖追踪
【4月更文挑战第24天】Vue的响应式原理通过JavaScript getter/setter实现,当数据变化时自动更新视图。它创建Watcher对象收集依赖,并通过依赖追踪机制精确通知更新。当属性改变,setter触发更新相关Watcher,重新执行操作以反映数据最新状态。Vue的响应式系统结合依赖追踪,有效提高性能,简化复杂应用的开发,但对某些复杂数据结构需额外处理。
|
2天前
|
缓存 JavaScript
【vue】如何搭建拦截器和设置路由守卫(基于token认证)
【vue】如何搭建拦截器和设置路由守卫(基于token认证)
14 0