Vue 选项式 API 与组合式 API 的对比与选择指南(2025–2026 视角)
Vue 目前(Vue 3 + Vue 3.5+)同时支持两种主要代码组织方式:
- 选项式 API(Options API)—— Vue 2 的经典写法,Vue 3 完全兼容
- 组合式 API(Composition API)—— Vue 3 引入的新范式,
<script setup>是其最常用语法糖
下面用真实场景对比的方式,帮助你清晰理解两者的差异、优缺点以及实际项目中该如何选择。
1. 核心对比表格(2025–2026 真实项目视角)
| 维度 | 选项式 API (Options API) | 组合式 API (Composition API) + <script setup> | 胜出方(大多数场景) |
|---|---|---|---|
| 代码组织方式 | 按“选项”分组:data、methods、computed、watch… | 按“逻辑关注点”自由组合 | 组合式 |
| 逻辑复用能力 | mixin、extends(容易命名冲突、来源不清晰) | composable 函数(清晰、类型友好、可树摇) | 组合式 ★★★★★ |
| TypeScript 支持 | 中等(需要大量 as any 或类型断言) | 极好(类型推导优秀,ref/reactive 天然支持) | 组合式 ★★★★★ |
| 代码量(中大型组件) | 较多(setup 里逻辑分散在不同选项) | 更少、更紧凑(相关逻辑写在一起) | 组合式 |
| 学习曲线(新手) | 较低(结构固定,容易理解“什么放在哪里”) | 较高(需要理解 ref、reactive、toRefs、生命周期钩子) | 选项式(初期) |
| 学习曲线(有经验者) | 中等(大型组件容易变成“意大利面条”) | 较低(逻辑清晰,可读性高) | 组合式 |
| 性能 | 几乎相同 | 几乎相同(<script setup> 甚至稍有编译期优化) | 平手 |
| 社区趋势(2025–2026) | 仍然大量维护中的老项目在使用 | 新项目、官方文档、VitePress、Nuxt 3、Element Plus 等主流库默认推荐 | 组合式 |
| 官方推荐 | 兼容并继续支持,但新功能优先在组合式中实现 | 官方主推,未来新特性(如 <script setup> 的宏)优先 | 组合式 |
2. 代码对比(同一个功能两种写法)
需求:一个计数器组件,支持:
- 显示 count
- 双倍计算属性 double
- watch count 变化打印日志
- 按钮 +1、-1
选项式 API(Vue 2 / Vue 3 兼容写法)
<template>
<div>
<p>Count: {{ count }}</p>
<p>Double: {{ double }}</p>
<button @click="increment">+1</button>
<button @click="decrement">-1</button>
</div>
</template>
<script>
export default {
data() {
return {
count: 0
}
},
computed: {
double() {
return this.count * 2
}
},
watch: {
count(newVal, oldVal) {
console.log(`count 从 ${oldVal} 变为 ${newVal}`)
}
},
methods: {
increment() {
this.count++
},
decrement() {
this.count--
}
},
mounted() {
console.log('组件挂载完成')
}
}
</script>
组合式 API + <script setup>(Vue 3 推荐写法)
<template>
<div>
<p>Count: {{ count }}</p>
<p>Double: {{ double }}</p>
<button @click="increment">+1</button>
<button @click="decrement">-1</button>
</div>
</template>
<script setup>
import { ref, computed, watch, onMounted } from 'vue'
// 响应式状态
const count = ref(0)
// 计算属性
const double = computed(() => count.value * 2)
// 方法
const increment = () => count.value++
const decrement = () => count.value--
// 侦听器
watch(count, (newVal, oldVal) => {
console.log(`count 从 ${oldVal} 变为 ${newVal}`)
})
// 生命周期
onMounted(() => {
console.log('组件挂载完成')
})
</script>
3. 组合式 API 的真正优势在“中大型组件”和“逻辑复用”
真实场景对比:一个包含表单校验、远程搜索、分页、权限控制的“用户管理表格”组件
选项式写法很容易出现:
- data 里 20+ 个属性
- methods 里 15+ 个方法
- watch 里散落多个侦听器
- 生命周期钩子重复写相似的逻辑
组合式写法可以把相关逻辑聚合在一起:
<script setup>
import { ref, watch, onMounted } from 'vue'
import { useForm } from '@/composables/useForm'
import { useTable } from '@/composables/useTable'
import { usePermission } from '@/composables/usePermission'
// 表单逻辑
const { form, validate, resetForm } = useForm()
// 表格逻辑
const { dataSource, pagination, fetchData, loading } = useTable()
// 权限逻辑
const { hasEditPerm, hasDeletePerm } = usePermission('user:manage')
// 统一加载数据
onMounted(fetchData)
</script>
→ 每个 composable 函数都是可独立测试、可复用、可类型推导的模块。
4. 2025–2026 年实际项目中的选择建议
| 项目类型 | 推荐写法 | 理由简述 |
|---|---|---|
| 全新项目(Vue 3) | 组合式 + <script setup> | 官方主推、生态最好、类型支持最强 |
| 维护中的 Vue 2 项目 | 继续选项式 | 最小改动成本 |
| Vue 2 → Vue 3 迁移项目 | 选项式 + 组合式 混用 | 逐步把复杂组件改成组合式 |
| 中大型组件(>200行) | 强烈推荐组合式 | 逻辑组织清晰度差距非常明显 |
| 需要大量逻辑复用 | 组合式(composable) | mixin 几乎被淘汰 |
| 团队新手较多 | 先用选项式,逐步过渡 | 学习曲线更平滑 |
| 追求极致开发体验 + TS | 组合式 + <script setup> | 当前最佳实践 |
5. 快速判断:我该用哪一种?
问自己这几个问题(按优先级):
- 组件是否已经/即将超过 150–200 行?→ 是 → 组合式
- 是否大量使用 TypeScript?→ 是 → 组合式
- 是否需要把一段逻辑在多个组件复用?→ 是 → 组合式(composable)
- 团队大部分人 Vue 2 经验丰富但 Vue 3 刚上手?→ 先选项式,逐步过渡
- 是全新项目或新模块?→ 组合式
大多数现代 Vue 3 项目(尤其是 2024 年后新建的)已经默认使用 <script setup> + 组合式 API。
如果你现在还在犹豫,可以先在一个新页面/新组件里尝试用 <script setup> 写一次,感受一下逻辑组织上的差异,大部分人写过 2–3 个组件后就会倾向于组合式。
有具体组件代码想对比两种写法,或者想看某个典型场景(表单 + 表格 + 弹窗)的组合式写法示例吗?可以直接贴代码或描述需求~