Vue 函数式组件是一种特殊的组件,它没有实例(即没有 this
上下文),并且是无状态的。
函数式组件的主要用途是作为渲染函数的包装器,用于更高效地渲染组件,尤其是在需要大量渲染简单组件的场景中。
一、函数式组件的特点
(一)无状态
函数式组件不包含任何状态(data
),也不支持生命周期钩子。它们的输出完全依赖于它们的输入(props
)。
(二)无实例
函数式组件没有实例,因此不支持 this
上下文。这意味着你不能在函数式组件内部访问 this
,也不能使用 this
来访问 data
、methods
等。
(三)高效渲染
由于函数式组件没有实例和状态,它们的渲染过程更加高效。Vue 在内部对函数式组件进行了优化,减少了不必要的开销。
二、函数式组件的定义和使用
(一)定义函数式组件
在 Vue 2.x 中,可以通过设置组件选项的 functional: true
来定义函数式组件。在 Vue 3.x 中,函数式组件通常使用 setup
函数来定义。
1. Vue 2.x 示例
// MyFunctionalComponent.vue
<template>
<div>
<h1>{{ title }}</h1>
<p>{{ content }}</p>
</div>
</template>
<script>
export default {
functional: true,
props: {
title: String,
content: String
},
// h: CreateElement
render(h, { props }) {
return h('div', [
h('h1', props.title),
h('p', props.content)
]);
}
};
</script>
2. Vue 3.x 示例
在 Vue 3.x 中,函数式组件通常使用 setup
函数来定义,但也可以直接使用 h
函数来定义。
// MyFunctionalComponent.vue
<template>
<div>
<h1>{{ title }}</h1>
<p>{{ content }}</p>
</div>
</template>
<script>
import { h } from 'vue';
export default {
props: {
title: String,
content: String
},
setup(props) {
return () => h('div', [
h('h1', props.title),
h('p', props.content)
]);
}
};
</script>
(二)使用函数式组件
函数式组件的使用方式与其他组件相同,通过 props
传递数据。
<MyFunctionalComponent :title="'Hello'" :content="'This is a functional component'" />
(三)场景:模版中定义、使用临时变量
将属性返回给调用方
// TempVar.js
export default {
functional: true,
render: (E, ctx) => {
return ctx.scopedSlots.default && ctx.scopedSlots.default(ctx.props || {});
}
};
// Functional.vue
<template functional>
<div>
{{ props }}
</div>
</template>
使用
<template>
<div>
<a-tabs>
<a-tab-pane key="Functional" tab="函数式组件">
<Functional :name="name"/>
// 定义临时变量: var1、var2
// TempVar 将属性返回给调用方
<TempVar
:var1="`hello ${name}`"
:var2="destroyClock ? 'hello vue' : 'hello world'"
>
// 接受变量并使用临时变量,可以写复杂的逻辑
<template v-slot="{ var1, var2 }">
{{ var1 }}
{{ var2 }}
</template>
</TempVar>
</a-tab-pane>
</a-tabs>
</div>
</template>
<script>
import Functional from "./Functional";
import TempVar from "./TempVar";
export default {
components: {
Functional,
TempVar
},
data() {
return {
destroyClock: false,
name: "vue"
};
}
};
</script>