Vue3 定义组件的 4 种方式,你真的选对了吗?

大家好,我是 前端架构师 - 大卫

初心为助前端人🚀,进阶路上共星辰✨,

您的点赞👍与关注❤️,是我笔耕不辍的灯💡。

更多优质内容,欢迎关注我的公众号 @前端大卫,一起探索前端技术的无限可能!

背景

Vue 作为一款流行的前端框架,提供了多种方式来定义组件,包括单文件组件 (SFC)、渲染函数 (Render Functions)、JSX/TSX 以及函数式组件 (Functional Components)。不同的方式适用于不同的场景,开发者在选择时需要考虑可读性、性能和灵活性等因素。本文将对这四种方式进行详细对比,帮助你找到最适合自己项目的方案。

1. SFC (Single-File Component)

单文件组件,以 *.vue 作为文件扩展名,是 Vue 官方推荐的方式。

特点:

  • 模板和逻辑分离,结构清晰,官方推荐。
  • 支持 Vue 内置功能,如 script setup、CSS 作用域、单文件组件热更新等。
  • 适合大多数 Vue 项目,代码组织更直观。

Test.vue 代码如下:

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

特点:

  • 需要引入 hdefineComponent 函数,没有模板语法。
  • 适合动态组件或 UI 库开发。

h 是一个 helper 函数,用于创建虚拟 DOM(VNode)。它是 createElement 的别名,类似于 React 里的 React.createElement

Test.ts 代码如下:

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 需要配置:

json 复制代码
{
  "compilerOptions": {
    "jsx": "preserve",
    "jsxImportSource": "vue"
    // ...
  }
}

vite.config.ts 需要配置 vueJsx 插件:

ts 复制代码
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 代码如下:

ts 复制代码
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 代码如下:

ts 复制代码
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>
  );
};

优点:

  • 代码简单,适用于简单的展示组件 (如按钮、图标等)。
  • 没有响应式数据追踪开销,性能更高。

缺点:

  • 不能在组件内部使用 refreactive,状态必须是全局变量或 props 传入。
  • 全局 ref 可能导致多个组件实例共享状态,引发意外的状态同步问题。

总结

方式 适用场景 优点 缺点
SFC (单文件组件) 适用于大多数 Vue 项目 结构清晰、官方推荐、支持 script setup 需要构建工具
渲染函数 (Render Functions) 适用于动态组件/UI 库 代码更灵活,适用于动态 VNode 结构 可读性较低,维护成本高
JSX / TSX 适用于复杂逻辑组件 代码灵活,可与 TypeScript 结合 需要额外配置,不符合 Vue 传统语法
函数式组件 适用于无状态小组件 代码简单、性能较高 不能使用 ref,全局状态共享有风险

在实际开发中,SFC 是最推荐的方式 ,大多数 Vue 组件都可以用 SFC 实现。对于动态 VNode 结构,可以考虑 渲染函数JSX/TSX函数式组件 在 Vue 3 中的使用场景很少,通常不推荐使用。

如果本文对你有帮助,欢迎点赞❤️收藏⭐,也欢迎在评论区交流!

更多详细内容可参考: Vue 官方文档

相关推荐
普通网友33 分钟前
Web前端常用面试题,九年程序人生 工作总结,Web开发必看
前端·程序人生·职场和发展
站在风口的猪11082 小时前
《前端面试题:CSS对浏览器兼容性》
前端·css·html·css3·html5
青莳吖4 小时前
使用 SseEmitter 实现 Spring Boot 后端的流式传输和前端的数据接收
前端·spring boot·后端
CodeCraft Studio4 小时前
PDF处理控件Aspose.PDF教程:在 C# 中更改 PDF 页面大小
前端·pdf·c#
拉不动的猪4 小时前
TS常规面试题1
前端·javascript·面试
再学一点就睡5 小时前
实用为王!前端日常工具清单(调试 / 开发 / 协作工具全梳理)
前端·资讯·如何当个好爸爸
穗余5 小时前
NodeJS全栈开发面试题讲解——P5前端能力(React/Vue + API调用)
javascript·vue.js·react.js
Jadon_z5 小时前
vue2 项目中 npm run dev 运行98% after emitting CopyPlugin 卡死
前端·npm
一心赚狗粮的宇叔5 小时前
web全栈开发学习-01html基础
前端·javascript·学习·html·web
IT瘾君5 小时前
JavaWeb:前端工程化-ElementPlus
前端·elementui·node.js·vue