vue虚拟DOM和render()函数详解
vue虚拟DOM和render()函数
与其他的前端开发框架相比,Vue.js的优势是执行性能比较高,这里有一个很重要的原因就是Vue.js采用虚拟DOM机制。
虽然大多数情况下,Vue.js推荐使用模板构建HTML,但是在某些场景下,可能需要JavaScript的编程能力,这时就需要使用render()函数,它比模板更接近编辑器。
通过本章内容的学习,读者可以了解虚拟DOM和render()函数的使用方法。
虚拟DOM
DOM即文档对象模型,它提供了对整个文档的访问模型,将文档作为一个树形结构,树的每个结点表示了一个HTML标签或标签内的文本项。
DOM树结构精确地描述了HTML文档中标签间的相互关联性。浏览器在解析HTML文档时,会将文档中的元素、注释、文本等标记按照它们的层级关系转化为DOM树。
一个元素要想在页面中显示,则必须在DOM中存在该节点,也就是必须将该元素节点添加到现有DOM树中的某个节点下,才能渲染到页面中。同样地,如果需要删除某个元素,也需要从DOM树中删除该元素对应的节点。
如果每次要改变页面展示的内容,只能通过遍历查询DOM树,然后修改DOM树,从而达到更新页面的目的,这个过程相当消耗资源。
为了解决这个问题,虚拟DOM概念随着React的诞生而诞生,其由Facebook提出,其卓越的性能很快得到广大开发者的认可。因为每次查询DOM几乎都需要遍历整个DOM树,如果建立一个与DOM树对应的虚拟DOM对象,也就是JavaScript对象,以对象嵌套的方式来表示DOM树及其层级结构,那么每次DOM的修改就变成了对JavaScript对象的属性的操作,由于操作JavaScript对象比操作DOM要快得多,从而大幅度减少性能的开支。
Vue从2.0开始也在其核心引入了虚拟DOM的概念,Vue.js 3.x重写了虚拟DOM的实现,从而让性能更加优秀。
Vue在更新真实的DOM树之前,先比较更新前后虚拟DOM结构中有差异的部分,然后采用异步更新队列的方式将差异部分更新到真实DOM中,从而减少了最终要在真实DOM上执行的操作次数,提高了页面的渲染效率。
render()函数
大多数情况下,Vue通过template来创建HTML。但是在特殊情况下,可能需要JavaScript的编程能力,这时可以使用render()函数,它比模板更接近编译器。
下面通过一个简单的例子,了解render()函数的优势。假设需要生成一些带锚点的标题,基础代码如下:
<h1> <a name="hello-world" href="#hello-world" rel="external nofollow" rel="external nofollow" > Hello world! </a> </h1>
由于锚点标题的使用非常频繁,考虑到标题的级别包括h1~h6,可以将标题的级别定义成组件的prop,在调用组件时,可以通过该prop动态设置标题元素的级别。
代码如下:
<anchored-heading :level="1">Hello world!</anchored-heading>
接下来就是组件的实现代码:
const app = createApp({}) app.component(‘anchored-heading', { template: ` props: { level: { type: Number, required: true } } })
上述通过模板的方式实现起来不仅冗长,而且为每个级别标题都重复书写了。
当添加锚元素时,还必须在每个 v-if/v-else-if 分支中再次复制元素。
<div id="app"> <anchored-heading :level="2"> <a name="hello-world" href="#hello-world" rel="external nofollow" rel="external nofollow" > 相顾无相识,长歌怀采薇。 </a> </anchored-heading> </div> <script src="https://unpkg.com/vue@next"></script> <script> const app = Vue.createApp({}) app.component('anchored-heading', { render() { const { h } = Vue return h( 'h' + this.level, // 标签名 {}, // prop 或 attribute this.$slots.default() // 包含其子节点的数组 ) }, props: { level: { type: Number, required: true } }) app.mount('#app') </script>
可见使用render()函数的实现要精简得多。
需要注意的是:
向组件中传递不带v-slot指令的子节点时,比如 anchored-heading 中的 Hello world!,这些子节点被存储在组件实例中的$slots.default中。在谷歌浏览器中运行程序。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
最新评论