Vue 3 组合式 API 完全指南:setup 与 composables 实战
Vue 3 提供了两套组件书写方式:Options API 与 Composition API。官方推荐的现代方式是"组合式 API + <script setup> + 单文件组件(SFC)"——它把同一业务逻辑的代码聚在一起,天然支持逻辑复用。对建站团队而言,Vue 3 既能为静态页做渐进式增强,也能支撑完整的单页应用与 SSR 场景。
Vue 相关内容属于前端搭建分类;若想横向对比框架选型,可参考前端框架对比。
以一次真实重构为例:一个后台管理页有 40 多个表单字段、涉及三个接口的联动校验。用 Options API 写,methods 里塞了 300 多行互相引用的函数,改一处常常要翻好几个区块。迁到组合式 API 后,校验逻辑收敛成三个 composable,状态、请求、错误处理各归其位,同样功能代码量少了近一半,同事接手也更快。这类"逻辑密度高"的组件,正是组合式 API 收益最明显的地方。
一、两种 API 风格
Options API 用 data、methods、mounted 等选项组织代码,围绕 this 组件实例展开,对新手更友好。Composition API 则把逻辑写成普通函数,在 <script setup> 中直接使用顶层变量与函数,代码组织更自由,也更容易做复用与类型推导。二者共享同一套响应式内核——Options API 底层就是基于 Composition API 实现的。
二、<script setup>:更少的样板代码
<script setup> 是单文件组件中的编译时语法糖:导入的组件、顶层变量与函数会自动暴露给模板,无需 setup() 返回值,也无需 export default。
<script setup>
import { ref } from 'vue'
const count = ref(0)
function increment() {
count.value++
}
</script>
<template>
<button @click="increment">Count is: {{ count }}</button>
</template>
三、响应式状态与 computed/watch
ref 把基本类型包装成响应式引用,reactive 用于对象;computed 派生数据,watch/watchEffect 侦听变化。组合式 API 允许在函数作用域中直接声明这些状态,再通过函数组合来应对复杂度。
实际开发中 computed 和 watch 的分工值得说清:computed 适合"由已有状态派生新值"的场景,比如购物车合计、筛选后的列表,它会被缓存、只在依赖变化时重算;watch 适合"状态变化后需要执行副作用"的场景,比如搜索框输入后防抖请求、路由变化后重置表单。如果只是要展示一个派生值,优先用 computed,让模板保持声明式;只有确需在变化时"做事"才用 watch。判断标准很简单:模板里直接能算出来的,就别写到 watch 里。
四、composables:逻辑复用与代码组织
composable 是"利用组合式 API 封装可复用状态逻辑"的函数,约定以 use 开头。鼠标位置跟踪、接口请求、表单校验等都能封装成 composable,还能互相嵌套组合。相比 Vue 2 的 mixins,composables 解决了属性来源不清、命名冲突与隐式耦合三大问题,是 Vue 3 推荐的复用方式。
// useFetch.js
import { ref, watchEffect, toValue } from 'vue'
export function useFetch(url) {
const data = ref(null)
const error = ref(null)
watchEffect(() => {
data.value = null
error.value = null
fetch(toValue(url))
.then((res) => res.json())
.then((json) => (data.value = json))
.catch((err) => (error.value = err))
})
return { data, error }
}
上面的 useFetch 同时接受字符串、ref 与 getter,toValue 负责统一取值,watchEffect 负责在依赖变化时重新请求——异步状态(加载/成功/失败)由此收敛到一处。
五、从 Options API 迁移
迁移不必一步到位,可以按组件逐个推进。下面是一张常用的映射表:
| Options API | Composition API |
|---|---|
data() |
ref() / reactive() |
computed |
computed() |
methods |
普通函数 |
watch |
watch() / watchEffect() |
mounted / unmounted |
onMounted() / onUnmounted() |
mixins |
composables |
一个实用建议:优先迁移"逻辑密度高"的组件(表单、列表、数据请求),纯展示组件保留 Options API 也完全没问题,不必为了"统一"而强制重写。迁移时可以先用 <script setup> 与 Options API 混用过渡,再逐步把 data/methods 收敛进组合式写法。
六、composables 最佳实践
- 命名:camelCase 且以
use开头 - 返回值:约定返回普通对象(内含多个 ref),便于解构时保持响应性
- 副作用:SSR 场景把 DOM 副作用放进
onMounted,并在onUnmounted清理 - 调用位置:仅在
<script setup>或setup()中同步调用
一个可复用的经验:把"状态 + 请求 + 清理"封装成 composable 后,组件里只剩声明式的调用,比如 const { data, error, retry } = useFetch('/api/user')。这样即使接口列表或参数变化,改动也只集中在一个文件里,团队成员不需要翻遍每个组件去理解数据是怎么来的,代码的可读性与可维护性都会明显提升。
六、工程化落地
Vue 3 官方工具链包括 Vite(详见Vite 构建工具指南)、Vue Router 与 Pinia。配合 TypeScript 时,<script setup> 能获得很强的类型推导(可参考TypeScript 实战指南)。组件样式可直接使用 Tailwind(Tailwind 页面模板),或参考HTML 页面模板。
常见疑问
要不要把全站都改成 <script setup>? 不必。Vue 官方允许两种风格共存,建议新组件用组合式 API,存量组件按业务价值分批迁移。
ref 和 reactive 怎么选? 社区主流做法是优先用 ref(配合 toRefs/computed 足够覆盖绝大多数场景),对象深层结构复杂时再考虑 reactive;ref 的解构与传参语义也更简单,容易推导。
composable 里能用另一个 composable 吗? 可以,只要都在 <script setup> 或 setup() 中同步调用,组合式函数可以自由嵌套,这也是它与 mixins 的关键区别之一。
原文来源:https://vuejs.org/guide/introduction.html
参考:Vue 3 组合式 API FAQ https://vuejs.org/guide/extras/composition-api-faq.html