函数式组件概念
函数式组件有以下特点:
- functional true
- 无状态,无实例,没有this上下文,没有生命周期
在 Vue 2 中,函数式组件有两个主要用例: 作为性能优化,因为它们的初始化速度比有状态组件快得多 返回多个根节点 然而,在 Vue 3 中,有状态组件的性能已经提高到可以忽略不计的程度。此外,有状态组件现在还包括返回多个根节点的能力。因此,函数式组件剩下的唯一用例就是简单组件,比如创建动态标题的组件。否则,建议你像平常一样使用有状态组件。
以官方文档中通过一个level prop 动态生成标题 (heading) 的组件举例,普通写法是:
<template>
<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>
</template>
<script>
export default {
name: 'heading',
props: {
level: {
type: Number,
default: 1,
requited: true
}
}
}
</script>
<heading :level="2">Heading</heading>
用render改写
<script>
export default {
name: 'render-heading',
created () {
console.log('RenderHeading created')
},
render: function (createElement) {
return createElement(
'h' + this.level, // 标签名称
this.$slots.default // 子节点数组
)
},
props: {
level: {
type: Number,
required: true
}
}
}
</script>
我们用render替换了template的写法,代码精简很多,而且此时还是带状态的组件,用created钩子函数能监听到组件的生命周期。
2.X语法
如果要改写为函数式组件,只需增加一个functional: true,,并且修改render函数为:
render (h, {props, data, children}) {
return h(`h${props.level}`, data, children)
},
此时已经变成一个函数式组件了,没有生命周期,也就打印不出"RenderHeading created"。
3.X语法
现在在 Vue 3 中,所有的函数式组件都是用普通函数创建的,换句话说,不需要定义 { functional: true } 组件选项。
他们将接收两个参数:props 和 context。context 参数是一个对象,包含组件的 attrs,slots,和 emit property。
此外,现在不是在 render 函数中隐式提供 h,而是全局导入 h。
使用前面提到的 <render-heading> 组件的示例,下面是它现在的样子。
import { h } from 'vue'
const RenderHeading = (props, context) => {
return h(`h${props.level}`, context.attrs, context.slots)
}
RenderHeading.props = ['level']
export default RenderHeading
用函数式组件做临时变量
这个用法是参考唐金州的视频教程。
我们可以通过函数式组件做临时变量,computed也可以实现临时变量,但是computed必须依赖全局响应式数据,在某些情况下你可能想用非全局的临时变量。
创建一个tempVar.js
export default {
functional: true,
render: (h, ctx) => {
return ctx.scopedSlots.default && ctx.scopedSlots.default(ctx.props || {})
}
}
这个组件直接把props属性返回给调用方,然后在传入一个template的v-slot中,在这个template内部就可以直接使用我们定义的props变量了,这就是一个临时变量。
<TempVar
:var1="`hello ${name}`"
>
<!-- 接收 prop 的具名插槽 -->
<template v-slot="{var1}">
{{ var1 }}
</template>
</TempVar>