Vue 3 组合式 API 完全指南:从入门到实践一

发布于2026-03-24 09:20 阅读26次 详细介绍Vue 3组合式API的使用方法,包括ref、reactive、computed等核心功能的深入讲解,以及Composables逻辑复用技巧的完整实践,帮助开发者快速掌握Vue3开发精髓。
# Vue 3 组合式 API 完全指南:从入门到实践
## 引言
Vue 3 带来的最大变革之一就是组合式 API(Composition API)的引入。作为一名 Vue 开发者,如果你还在使用 Options API 开发项目,那么是时候认真了解一下这个强大的新特性了。组合式 API 不仅能够让代码组织更加清晰,还能大幅提升 TypeScript 支持,更重要它让逻辑复用变得前所未有的简单。
## 什么是组合式 API?
组合式 API 是 Vue 3 引入的一套新的 API 体系,它允许我们以函数的形式来定义组件逻辑。与传统的 Options API 相比,组合式 API 提供了更灵活的代码组织方式,让我们能够根据功能而非选项类型来组织代码。
在 Vue 2 中,我们使用 Options API 来定义组件,代码通常按照 data、methods、computed、watch 等选项来组织。这种方式对于小型项目来说非常直观,但随着项目规模增大,特别是当组件包含大量相关逻辑时,同一个功能的代码可能被拆散到不同的选项中,导致维护困难。
组合式 API 彻底解决了这个问题。通过使用 setup() 函数,我们可以在同一个地方定义所有与特定功能相关的响应式状态和逻辑。这不仅让代码更容易理解,还使得逻辑复用变得异常简单。
## setup 函数详解
setup() 是组合式 API 的入口点,它在组件创建之前执行,此时 DOM 还未挂载。setup 函数接收两个参数:props 和 context。
```javascript
import { ref, onMounted } from "vue"
export default {
setup(props, context) {
// props 是响应式的
console.log(props.title)
// context 是一个普通对象,包含 attrs、emit、slots
const handleClick = () => {
context.emit("update", "some data")
}
return {
handleClick
}
}
}
```
值得注意的是,setup 函数中定义的所有变量和函数都需要通过 return 语句暴露出去,才能在模板中使用。这是组合式 API 与 Options API 的一个重要区别。
## 响应式系统核心
### ref 和 reactive
Vue 3 提供了两种创建响应式数据的方式:ref 和 reactive。
ref 用于创建基础类型的响应式数据,比如字符串、数字、布尔值等。使用 ref 时,需要通过 .value 来访问或修改值,但在模板中会自动解包,无需使用 .value。
```javascript
import { ref } from "vue"
const count = ref(0)
const message = ref("Hello Vue 3")
function increment() {
count.value++
}
```
reactive 用于创建对象类型的响应式数据。与 ref 不同,reactive 返回的是原始对象的 Proxy,不需要使用 .value。
```javascript
import { reactive } from "vue"
const state = reactive({
name: "Vue",
version: 3,
features: ["Composition API", "Teleport", "Fragments"]
})
function updateName() {
state.name = "Vue.js"
}
```
在实际开发中,我建议遵循以下原则:基础类型使用 ref,对象类型使用 reactive。这样可以让代码意图更加清晰。
### computed 和 watch
computed 用于创建计算属性,它会自动追踪依赖并缓存结果。只有当依赖发生变化时,计算属性才会重新计算。
```javascript
import { ref, computed } from "vue"
const firstName = ref("John")
const lastName = ref("Doe")
const fullName = computed(() => {
return firstName.value + " " + lastName.value
})
```
watch 用于监听响应式数据的变化并执行相应的回调函数。Vue 3 的 watch 不仅可以监听单个数据源,还可以监听多个数据源。
```javascript
import { ref, watch } from "vue"
const count = ref(0)
watch(count, (newValue, oldValue) => {
console.log(`Count changed from ${oldValue} to ${newValue})`
})
```
## 生命周期钩子的组合式写法
组合式 API 提供了对应于 Options API 生命周期的钩子函数。需要注意的变化是,beforeCreate 和 created 被 setup() 替代,其他钩子则有了新的函数形式。
```javascript
import {
onMounted,
onUpdated,
onUnmounted,
onBeforeMount,
onBeforeUpdate,
onBeforeUnmount
} from "vue"
export default {
setup() {
onBeforeMount(() => {
console.log("组件即将挂载")
})
onMounted(() => {
console.log("组件已挂载")
// 这里可以执行 DOM 操作
})
onBeforeUpdate(() => {
console.log("组件即将更新")
})
onUpdated(() => {
console.log("组件已更新")
})
onBeforeUnmount(() => {
console.log("组件即将卸载")
})
onUnmounted(() => {
console.log("组件已卸载")
// 清理定时器、事件监听器等
})
return {}
}
}
```
这种写法的一个巨大优势是,我们可以在不同的逻辑块中分别注册生命周期钩子,而不必像 Options API 那样把所有 onMounted 代码都写在一起。
## 依赖注入:provide 和 inject
Vue 3 提供了 provide 和 inject 来实现跨组件层级共享数据。这在处理深层组件通信时特别有用。
```javascript
// 父组件
import { provide, ref } from "vue"
export default {
setup() {
const theme = ref("dark")
provide("theme", theme)
provide("appName", "My Vue App")
return {}
}
}
```
```javascript
// 子组件
import { inject } from "vue"
export default {
setup() {
const theme = inject("theme")
const appName = inject("appName")
return { theme, appName }
}
}
```
provide 和 inject 默认是响应式的,如果想让数据变化后子组件能够感知到,需要使用 ref 或 reactive 包装数据。
## 逻辑复用:Composables
组合式 API 最强大的应用场景之一就是逻辑复用。通过创建可复用的组合式函数(Composables),我们可以将组件逻辑提取出来,在多个组件之间共享。
### 示例:鼠标位置追踪
```javascript
// useMouse.js
import { ref, onMounted, onUnmounted } from "vue"
export function useMouse() {
const x = ref(0)
const y = ref(0)
function update(event) {
x.value = event.pageX
y.value = event.pageY
}
onMounted(() => {
window.addEventListener("mousemove", update)
})
onUnmounted(() => {
window.removeEventListener("mousemove", update)
})
return { x, y }
}
```
### 示例:异步数据获取
```javascript
// useFetch.js
import { ref } from "vue"
export function useFetch(url) {
const data = ref(null)
const error = ref(null)
const loading = ref(true)
fetch(url)
.then(res => res.json())
.then(json => {
data.value = json
loading.value = false
})
.catch(err => {
error.value = err
loading.value = false
})
return { data, error, loading }
}
```
使用这些 Composables 非常简单:
```javascript
import { useMouse } from "./useMouse"
import { useFetch } from "./useFetch"
export default {
setup() {
const { x, y } = useMouse()
const { data, error, loading } = useFetch("/api/user")
return { x, y, data, error, loading }
}
}
```
这就是 Vue 3 组合式 API 的魔力所在。通过将逻辑封装成独立的函数,我们可以轻松地在不同组件间复用代码,同时保持代码的清晰和组织性。
## TypeScript 支持
组合式 API 对 TypeScript 的支持远超 Options API。借助类型推断,我们可以获得完整的类型检查和智能提示。
```typescript
import { ref, computed } from "vue"
interface User {
id: number
name: string
email: string
}
const user = ref<User | null>(null)
const userName = computed(() => user.value?.name ?? "")
function setUser(newUser: User) {
user.value = newUser
}
```
对于 Composables,TypeScript 的支持同样出色。我们可以完全类型化我们的组合式函数,确保使用时获得正确的类型推断。
## 实际项目中的最佳实践
### 1. 合理组织代码结构
在一个复杂的组件中,我建议按照以下顺序组织代码:
```javascript
export default {
setup(props) {
// 1. 常量和静态配置
const API_URL = "/api/v1"
// 2. 响应式状态
const loading = ref(false)
const data = ref([])
const error = ref(null)
// 3. 计算属性
const hasData = computed(() => data.value.length > 0)
const isEmpty = computed(() => !loading.value && !hasData.value)
// 4. 方法
async function fetchData() {
loading.value = true
try {
const response = await fetch(API_URL)
data.value = await response.json()
} catch (e) {
error.value = e
} finally {
loading.value = false
}
}
// 5. 生命周期钩子
onMounted(() => {
fetchData()
})
// 6. 监听器
watch(() => props.id, () => {
fetchData()
})
// 7. 提供给模板的内容
return {
loading,
data,
error,
hasData,
isEmpty,
fetchData
}
}
}
```
### 2. 使用解构保持响应性
有时候我们需要从 props 或其他响应式对象中解构数据。需要注意的是,直接解构会丢失响应性。
```javascript
// 错误做法 - 会丢失响应性
const { name, age } = props
// 正确做法 1 - 使用 toRef
import { toRef } from "vue"
const name = toRef(props, "name")
const age = toRef(props, "age")
// 正确做法 2 - 使用 toRefs
import { toRefs } from "vue"
const { name, age } = toRefs(props)
```
### 3. 避免响应式陷阱
Vue 的响应式系统非常智能,但在某些情况下也需要特别注意:
```javascript
// 不要这样做 - 破坏响应性
const obj = reactive({ name: "Vue" })
const newObj = obj // 这只是引用,不是复制
// 正确做法 - 如果需要副本
const newObj = reactive({ ...obj })
// 或者
const newObj = toRaw(obj) // 获取原始对象后重新包装
```
## 迁移策略
如果你有一个 Vue 2 项目想要迁移到 Vue 3,不需要一次性将所有代码重写为组合式 API。我建议采用渐进式迁移策略:
首先,在新功能中使用组合式 API。新建的组件和模块直接采用新的 API 开发。然后,逐步将可复用的逻辑抽取为 Composables。这样做的好处是可以立竿见影地改善代码组织,而不需要大规模重构。
Vue 3 同时支持 Options API 和组合式 API,所以你可以根据实际情况灵活选择。对于简单组件,Options API 依然是一个很好的选择。
## 总结
Vue 3 的组合式 API 为我们带来了全新的开发体验。它让代码组织更加清晰,逻辑复用变得更加简单,对 TypeScript 的支持也更加完善。虽然学习曲线比 Options API 略高,但一旦掌握,你一定会爱上这种开发方式。
组合式 API 不仅仅是一个 API 层面的更新,更是一种编程思维的转变。它鼓励我们将相关的逻辑组织在一起,而不是按照选项类型分散代码。这种方式更符合人类的思维习惯,也让大型项目的维护变得更加可控。
作为 Vue 开发者,我强烈建议大家深入学习组合式 API,并在实际项目中尝试使用。相信你会发现,这一切都值得。