1. 组合式 API 设计哲学与核心优势
Vue 3 的组合式 API 不是简单的语法糖,而是一次彻底的设计范式转变。它解决了选项式 API 在复杂组件中面临的代码碎片化问题,让开发者能够像搭积木一样自由组合逻辑片段。我在多个中大型项目中实践后发现,组合式 API 最显著的优势体现在三个方面:
首先,逻辑关注点聚合。在传统的选项式 API 中,一个用户管理功能的代码会被分散到 data、methods、computed 等不同选项中。而使用组合式 API 后,所有相关代码可以集中在一个 useUser 函数中,就像这样:
typescript复制// 传统选项式API的代码分布
export default {
data() {
return { users: [], loading: false }
},
methods: {
fetchUsers() { /* ... */ }
},
computed: {
activeUsers() { /* ... */ }
}
}
// 组合式API的实现
function useUserManagement() {
const users = ref<User[]>([])
const loading = ref(false)
const activeUsers = computed(() =>
users.value.filter(u => u.isActive)
)
async function fetchUsers() {
loading.value = true
users.value = await userService.getAll()
loading.value = false
}
return { users, loading, activeUsers, fetchUsers }
}
其次,类型推导更加友好。Vue 2 的选项式 API 对 TypeScript 的支持始终存在各种边界情况,而组合式 API 的变量和函数都是标准的 JavaScript 声明,能获得完美的类型推断。我在迁移企业级项目到 Vue 3 时,TypeScript 报错减少了约 70%。
第三,逻辑复用成本大幅降低。以前要通过 mixin 或高阶组件实现的逻辑复用,现在只需要将相关代码提取为 composable 函数即可。更重要的是,这些 composable 可以清晰地声明输入输出,避免了 mixin 的属性名冲突问题。
提示:从选项式迁移到组合式时,建议采用渐进式策略。可以先在现有组件中使用 setup() 函数处理新功能,再逐步迁移旧逻辑,而不是一次性重写整个组件。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 项目结构与代码组织实践
2.1 功能优先的目录架构
在大型项目中,我推荐采用"功能优先"的目录结构。与传统的按技术角色划分(components、views、store 等)不同,功能式组织将同一业务域的所有代码放在一起:
code复制src/
features/
user/
composables/
useUserList.ts
useUserForm.ts
components/
UserList.vue
UserForm.vue
types.ts
index.ts
product/
composables/
useProductSearch.ts
components/
ProductCard.vue
...
这种结构的优势在于:
- 修改功能时所有相关文件都在同一目录下
- 更容易识别未使用的代码
- 方便进行功能模块的提取或迁移
2.2 组件级别的代码组织
对于复杂组件,我习惯采用"组件+composable"的配对模式。比如一个用户列表组件:
code复制UserList/
index.vue // 主入口
composables/
usePagination.ts
useFilter.ts
components/
UserRow.vue
FilterPanel.vue
types.ts
在 index.vue 中只需:
typescript复制import { usePagination, useFilter } from './composables'
const { paginatedData } = usePagination()
const { filters } = useFilter()
经验分享:当发现组件超过 300 行代码时,就应该考虑拆分为多个 composable。我通常以"一个 composable 处理一个子功能"为原则进行拆分。
3. 响应式数据深度解析
3.1 ref 与 reactive 的选用标准
经过多个项目的实践验证,我总结出以下选用原则:
- ref 适用场景:
- 基本类型值(string、number、boolean)
- 需要保持引用稳定的对象(如需要在 reactive 中嵌套)
- 模板中需要直接使用的值(因为 .value 在模板中会自动解包)
typesc复制
