Vue3定义组件的四种方式
作者:前端大卫
Vue 作为一款流行的前端框架,提供了多种方式来定义组件,包括单文件组件、渲染函数、、JSX/TSX 以及函数式组件、不同的方式适用于不同的场景,本文将对这四种方式进行详细对比,帮助你找到最适合自己项目的方案,需要的朋友可以参考下
背景
Vue 作为一款流行的前端框架,提供了多种方式来定义组件,包括单文件组件 (SFC)、渲染函数 (Render Functions)、JSX/TSX 以及函数式组件 (Functional Components)。不同的方式适用于不同的场景,开发者在选择时需要考虑可读性、性能和灵活性等因素。本文将对这四种方式进行详细对比,帮助你找到最适合自己项目的方案。
1. SFC (Single-File Component)
单文件组件,以 *.vue 作为文件扩展名,是 Vue 官方推荐的方式。
特点:
- 模板和逻辑分离,结构清晰,官方推荐。
- 支持 Vue 内置功能,如
script setup、CSS 作用域、单文件组件热更新等。 - 适合大多数 Vue 项目,代码组织更直观。
Test.vue 代码如下:
<script setup lang="ts">
import { ref } from "vue";
defineProps<{
text: string;
}>();
const num = ref(0);
</script>
<template>
<div class="aaa">
{{ text }}
<div @click="num++">{{ num }}</div>
</div>
</template>
优点:
- 代码结构清晰,符合 MVVM 模式,模板部分易读。
script setup提供更简洁的语法,减少模板和逻辑之间的代码切换。- 具有良好的工具链支持 (Vue 官方生态、Vite、Vue Loader 等)。
缺点:
- 需要额外的构建工具 (如 Vite 或 Webpack) 进行编译,不能直接在浏览器运行。
- 在某些场景下 (如动态创建组件) 可能不如渲染函数灵活。
2. 渲染函数 (Render Functions)
Vue 提供了一个 h() 函数用于创建虚拟节点 vnodes。
特点:
- 需要引入
h和defineComponent函数,没有模板语法。 - 适合动态组件或 UI 库开发。
h 是一个 helper 函数,用于创建虚拟 DOM(VNode)。它是 createElement 的别名,类似于 React 里的 React.createElement。
Test.ts 代码如下:
import { defineComponent, h, ref } from "vue";
export default defineComponent({
props: {
text: {
type: String,
required: true
}
},
setup(props) {
const num = ref(0);
return () =>
h("div", { class: "aaa" }, [props.text, h("div", { onClick: () => num.value++ }, num.value)]);
}
});
优点:
- 代码更灵活,适用于需要动态控制 VNode 结构的场景,如表单渲染器、可拖拽组件等。
- 体积更小,不需要 SFC 解析器。
缺点:
- 代码可读性较低,没有模板语法,编写复杂组件时维护成本较高。
- 开发体验不如 SFC 友好,特别是对于不熟悉 JSX/TSX 的开发者。
3. JSX / TSX
JSX 和 TSX 是 React 的语法扩展,Vue 也支持这种语法。
特点:
- 语法类似 React,允许在 Vue 组件中使用 JSX/TSX 语法。
- 适用于更灵活的逻辑处理,且无需引入
h()函数。
tsconfig.json 需要配置:
{
"compilerOptions": {
"jsx": "preserve",
"jsxImportSource": "vue"
// ...
}
}
vite.config.ts 需要配置 vueJsx 插件:
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import vueJsx from "@vitejs/plugin-vue-jsx";
export default defineConfig({
plugins: [vue(), vueJsx()]
// ...
});
Test.tsx 代码如下:
import { defineComponent, ref } from "vue";
export default defineComponent({
props: {
text: {
type: String,
required: true
}
},
setup(props) {
const num = ref(0);
return () => (
<div class="aaa">
{props.text}
<div onClick={() => num.value++}>{num.value}</div>
</div>
);
}
});
优点:
- 代码灵活,适用于复杂 UI 组件开发。
- 在 TypeScript 项目中拥有更好的类型推导支持。
缺点:
- 需要额外的
@vitejs/plugin-vue-jsx插件支持,并在tsconfig.json配置 JSX 选项。 - 代码风格不符合 Vue 传统的模板语法,可能不适合所有团队。
4. 函数式组件 (Functional Components) — 不推荐
特点:
- 组件本质上是一个纯函数,
ref只能定义在组件外部,属于全局共享状态。 - 适用于只依赖
props进行渲染,且无状态 (stateless) 的组件。
Test.tsx 代码如下:
import { ref, type FunctionalComponent } from "vue";
interface Props {
text: string;
}
const num = ref(0);
export const TestFunctionalCom: FunctionalComponent<Props> = (props) => {
return (
<div class="aaa">
{props.text}
<div onClick={() => num.value++}>{num.value}</div>
</div>
);
};
优点:
- 代码简单,适用于简单的展示组件 (如按钮、图标等)。
- 没有响应式数据追踪开销,性能更高。
缺点:
- 不能在组件内部使用
ref或reactive,状态必须是全局变量或props传入。 - 全局
ref可能导致多个组件实例共享状态,引发意外的状态同步问题。
总结
| 方式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| SFC (单文件组件) | 适用于大多数 Vue 项目 | 结构清晰、官方推荐、支持 script setup | 需要构建工具 |
| 渲染函数 (Render Functions) | 适用于动态组件/UI 库 | 代码更灵活,适用于动态 VNode 结构 | 可读性较低,维护成本高 |
| JSX / TSX | 适用于复杂逻辑组件 | 代码灵活,可与 TypeScript 结合 | 需要额外配置,不符合 Vue 传统语法 |
| 函数式组件 | 适用于无状态小组件 | 代码简单、性能较高 | 不能使用 ref,全局状态共享有风险 |
在实际开发中,SFC 是最推荐的方式,大多数 Vue 组件都可以用 SFC 实现。对于动态 VNode 结构,可以考虑 渲染函数 或 JSX/TSX。函数式组件 在 Vue 3 中的使用场景很少,通常不推荐使用。
以上就是Vue3定义组件的四种方式的详细内容,更多关于Vue3定义组件的资料请关注脚本之家其它相关文章!
