今天又看了一遍vue文档中的渲染函数,理解的差不多了,这里记录下,方便查阅,平时写的template组件vue内部通过正则匹配还是会编译成一棵虚拟节点树,最后放到渲染函数中去执行。
我们先用一个slot插槽的例子引出渲染函数:
很简单,Hello组件根据父组件传递的level值来判断渲染h1还是h2或h3 。
// Hello.vue
// Home.vue
hello world
span标签
上边写了好几个slot,代码有一些冗余!下边使用渲染函数改造下:
简单几行代码搞定,代码很简洁
// Hello.vue
参数一:String | Object | Function
最常用的是:标签或组件,如:'div'
参数二:一个模板中对应的数据对象,可选项,具体常用属性如下:
{
class: { foo: true, bar: false }, // 与 `v-bind:class` 的 API 相同
style: { color: 'red', fontSize: '14px' }, // 与 `v-bind:style` 的 API 相同
attrs: { id: 'foo' }, // 普通的 HTML attribute
props: { myProp: 'bar' }, // 组件 prop
on: { click: this.clickHandler }, // 点击事件
}
参数三:String | Array
如果是字符串,一定是标签里的文本节点,如果是数组,里边是子级虚拟节点 (VNodes),由 `createElement()` 构建而成。
理解刚开始的例子:
createElment函数中,参数一是标签;参数二,没有属性,直接给它一个空对象;参数三,一个数组,其中第一项是一个空字符串,表示创建的标签里边子元素最前边没有内容,第二项就是VNode了。
红框中的文本节点和元素节点,会传递到子组件中,
子组件render函数中,两个节点会被编译成虚拟子节点(VNodes),并且通过:this.$slots.default
可以获取到:
它是一个数组,
createElement返回什么:
下边是官方文档的解释,
createElement
到底会返回什么呢?其实不是一个实际的 DOM 元素。它更准确的名字可能是 createNodeDescription
,因为它所包含的信息会告诉 Vue 页面上需要渲染什么样的节点,包括及其子节点的描述信息。我们把这样的节点描述为“虚拟节点 (virtual node)”,也常简写它为“VNode”。“虚拟 DOM”是我们对由 Vue 组件树建立起来的整个 VNode 树的称呼。
(1)this.$slot
上边已经记录过,可以通过 this.$slot 访问静态插槽的内容(也就是默认插槽),每个插槽都是一个VNode数组:
export default {
functional: true,
render: function(createElement) {
console.log('$slot:', this.$slots.default)
return createElement('h1', {}, ['测试'])
},
data() {return{}}
}
(2)通过 this.$scopedSlots 访问作用于插槽,每个作用域插槽都是一个返回若干 VNode 的函数:
有什么用呢,我们可以通过 this.$scopedSlots.default() 传递参数,这样父级可以拿到该参数,进行处理,很方便!
// hello.vue
// home.vue
hello world
{
{msg}} // 会输出:{ "text": "123", "def": "456" }
函数式组件在开发中经常用的一张方式。
上边渲染函数,很简单,只是通过props接收了一些参数而已, 没有管理任何状态,也没有监听任何传递给它的状态,也没有生命周期方法。在这样的场景下,我们可以将组件标记为 functional:true,这意味它无状态 (没有响应式数据),也没有实例 (没有 this
上下文)。一个函数式组件就像这样 hello.vue :
// hello.vue
// 父组件 home.vue
hello world
span标签
组件需要的一切,可以通过ctx参数来获取、传递,ctx对象包含如下字段(下边的属性在上边例子中都有输出):
补充:
1、你也可以这样写,返回一个数组,数组中是标签:
参数一必须为h参数,否则无效或报错!
页面渲染如下:
2、通过 ctx.scopedSlots,可以编写一个临时变量
// com.js
export default {
functional: true,
render: function(createElement, ctx) {
console.log(ctx.scopedSlots.defualt())
return ctx.scopedSlots.defualt && ctx.scopedSlots.defualt({msg:ctx.props})
}
}
// Home.vue
{
{msg}} // 可以在这里边使用 { "text": "123", "def": "456" }