Vue 3 Composition API 实战:构建可复用的业务逻辑

发布于2026-03-30 00:18 阅读14次 本文通过实际业务场景,深入讲解Vue 3 Composition API的核心用法,包括响应式数据管理、自定义Hook封装、依赖注入等,帮助开发者从Options API平滑过渡到Composition API,提升代码复用性和可维护性。
## Vue 3 Composition API 实战:构建可复用的业务逻辑
Vue 3 引入的 Composition API 是框架历史上最重大的变革之一。与传统的 Options API 相比,Composition API 提供了更灵活的代码组织方式,让开发者能够按逻辑关注点组织代码,而非被迫按选项类型分散到不同的配置块中。本文将从实际业务场景出发,带你掌握 Composition API 的核心用法。
### 为什么选择 Composition API
在复杂业务组件中,Options API 的弊端显而易见。一个用户管理组件可能包含用户列表查询、表单验证、权限控制等多种逻辑,这些逻辑分散在 data、methods、computed、watch 等多个选项中,阅读和维护时需要反复跳转。Composition API 允许我们将相关逻辑聚合在一起,形成独立的、可复用的功能单元。
### 响应式数据:ref 与 reactive
Composition API 提供了两种创建响应式数据的方式:ref 和 reactive。ref 适用于基础类型和需要重新赋值的对象,reactive 则适用于对象结构稳定的场景。
```javascript
import { ref, reactive } from 'vue'
// 使用 ref 管理基础类型
const searchKeyword = ref('')
const currentPage = ref(1)
const pageSize = ref(10)
// 使用 reactive 管理复杂对象
const formState = reactive({
username: '',
email: '',
role: 'user',
status: true
})
```
需要注意的是,在模板中 ref 会自动解包,但在 JavaScript 中需要通过 .value 访问。reactive 则可以直接访问属性,但不能整体替换对象。
### 计算属性与侦听器
computed 用于派生状态,watch 和 watchEffect 用于响应数据变化执行副作用。
```javascript
import { computed, watch, watchEffect } from 'vue'
// 过滤后的用户列表
const filteredUsers = computed(() => {
return users.value.filter(user =>
user.name.includes(searchKeyword.value)
)
})
// 监听搜索关键词变化,重置分页
watch(searchKeyword, () => {
currentPage.value = 1
fetchUsers()
})
// 自动追踪依赖的副作用
watchEffect(() => {
document.title = `用户管理 - 第 ${currentPage.value} 页`
})
```
watch 与 watchEffect 的区别在于:watch 需要明确指定监听源,而 watchEffect 会自动收集回调中的响应式依赖。在需要精确控制触发条件的场景下,watch 更加合适。
### 自定义 Hook:逻辑复用的利器
Composition API 最强大的能力之一是自定义 Hook,也称为组合函数(Composables)。通过将业务逻辑封装为独立的函数,可以在多个组件中复用。
下面是一个分页查询 Hook 的实现:
```javascript
// usePagination.js
import { ref, watch } from 'vue'
export function usePagination(fetchFn, defaultPageSize = 10) {
const list = ref([])
const loading = ref(false)
const currentPage = ref(1)
const pageSize = ref(defaultPageSize)
const total = ref(0)
async function fetchData(params = {}) {
loading.value = true
try {
const res = await fetchFn({
page: currentPage.value,
size: pageSize.value,
...params
})
list.value = res.data
total.value = res.total
} catch (error) {
console.error('请求失败:', error)
} finally {
loading.value = false
}
}
function reset() {
currentPage.value = 1
fetchData()
}
// 页码变化时自动请求
watch(currentPage, () => fetchData())
watch(pageSize, () => {
currentPage.value = 1
fetchData()
})
return {
list, loading, currentPage, pageSize, total,
fetchData, reset
}
}
```
在组件中使用这个 Hook 非常简洁:
```javascript
import { usePagination } from '@/composables/usePagination'
import { getUserList } from '@/api/user'
const {
list: users,
loading,
currentPage,
pageSize,
total,
reset
} = usePagination(getUserList)
```
### 依赖注入:跨层级组件通信
在深层嵌套的组件树中,Props 逐层传递非常繁琐。provide 和 inject 提供了一种优雅的解决方案。
```javascript
// 父组件提供用户信息
import { provide, readonly } from 'vue'
const currentUser = ref(null)
provide('currentUser', readonly(currentUser))
// 任意子组件注入使用
import { inject } from 'vue'
const user = inject('currentUser')
```
使用 readonly 包裹提供的值可以防止子组件意外修改父组件状态,这是一种良好的实践。如果子组件需要修改,应该通过 provide 传递修改方法。
### 生命周期钩子
Composition API 中的生命周期钩子以 on 前缀命名,使用方式与 Options API 类似但更加灵活。
```javascript
import {
onMounted,
onUnmounted,
onBeforeUnmount
} from 'vue'
onMounted(() => {
fetchUsers()
window.addEventListener('resize', handleResize)
})
onBeforeUnmount(() => {
window.removeEventListener('resize', handleResize)
})
```
### 实战建议
第一,不要为了使用 Composition API 而过度拆分代码。如果一个组件逻辑简单,Options API 仍然是合理的选择。第二,自定义 Hook 应该保持单一职责,一个 Hook 只处理一个关注点。第三,善用 TypeScript 为 Hook 添加类型标注,提升开发体验和代码质量。
Composition API 并非完全取代 Options API,而是提供了一种更强大的代码组织方式。理解其设计理念,根据实际场景灵活选择,才能充分发挥 Vue 3 的能力。