渲染函数
背景
Vue推荐在绝大多数情况下使用模版来创建你的HTML。然后在一些场景中,你真的需要JavaScript的完全编程的能力。这时你可以用渲染函数,它比模版更接近编译器。
比如我需要根据传过来的数据来定义文本的标签:
<anchored-heading :level="1">Hello world!</anchored-heading>
子组件
<template>
<div>
<h1 v-if="level === 1">
<slot></slot>
</h1>
<h2 v-else-if="level === 2">
<slot></slot>
</h2>
<h3 v-else-if="level === 3">
<slot></slot>
</h3>
<h4 v-else-if="level === 4">
<slot></slot>
</h4>
<h5 v-else-if="level === 5">
<slot></slot>
</h5>
<h6 v-else-if="level === 6">
<slot></slot>
</h6>
</div>
</template>
<script>
export default {
export default {
props: ['level']
}
}
</script>
从上面代码我们可以看到标签没有办法动态化,只能分为多种情况,而且还要重复写<slot></slot>。虽然模版在大多数组件中都非常好用,但是显然在这里它就不合适了。那么我们来尝试使用render函数重写上面的例子:
import Vue from 'vue'
Vue.component('anchored-heading', {
render: function (createElement) {
return createElement(
'h' + this.level, // 标签名称
this.$slots.default // 子节点数组
)
},
props: {
level: {
type: Number,
required: true
}
}
})
以前我们都是用模版来创建HTML,Vue会将模版自动解析成代码生成器(详情看Vue模版编译原理),但是有的场景使用模版实现会比较麻烦或者无法实现,这时候我们就可以用渲染函数,渲染函数就是完成用Vue的js来实现。
基本用法
定义
Vue的模版实际上被编译成了渲染函数。
简单来说,在vue中我们使用模版来创建HTML,现在我们可以用render函数以js的方式来创建HTML。因为Vue是虚拟DOM,
虚拟DOM(Virtual Dom)
我们知道,浏览器在解析HTML时,会将HTML标签解析成一个DOM树。通过结构化的组织节点元素,浏览器可以很方便的跟踪整个页面的情况,但频繁的局部更新节点代价很高,因为会引发重排重绘。
Vue使用template的方式来创建HTML,还可以使用render函数来创建HTML,
为了更高效的渲染HTML,Vue和React根据真实DOM的映射构建对应的JS对象,也就是虚拟DOM。在数据和DOM之间创建一个缓冲地带,不用每次都更新DOM。
Vue通过render函数来创建一个节点描述对象(createNodeDescription),它所包含的信息会告诉Vue页面上需要渲染什么样的节点,包括子节点的描述信息。我们把这样的节点描述为虚拟节点,也常简写它为VNode。虚拟DOM是我们对由Vue组件树建立起来的整个VNode树的称呼。
项目中的页面一般都是动态的,如果改变页面的样式或结构都会触发页面的重排重绘,这个代价是比较高昂的,会破坏用户体验,并且让UI展示非常迟缓。
Vue使用render函数来创建虚拟dom,但是render函数的写法比较复杂,有点费解:
createElement(
'anchored-heading', {
props: {
level: 1
}
}, [
createElement('span', 'Hello'),
' world!'
]
)
特别是对应的模板如此简单的情况下:
<anchored-heading :level="1">
<span>Hello</span> world!
</anchored-heading>
这时候就推出了JSX语法,不过需要一个Babel插件来转译,它可以让我们回到更接近于模版的语法上。
import AnchoredHeading from './AnchoredHeading.vue'
new Vue({
el: '#demo',
render: function (h) {
return (
<AnchoredHeading level={1}>
<span>Hello</span> world!
</AnchoredHeading>
)
}
})
将 h 作为 createElement 的别名是 Vue 生态系统中的一个通用惯例,实际上也是 JSX 所要求的。
大佬说的:
我觉得是直接操作dom代价高,所以要在它上面加个虚拟dom,基于虚拟dom的差异比较结果再去操作真实dom
参考文章:https://github.com/berwin/Blog/issues/36
https://juejin.im/entry/582f16fca22b9d006b7afd89重拍重绘
https://juejin.im/entry/5b4b16a451882569fd2860c5
网友评论