Vue 3的组合式API(Composition API)为我们带来了更灵活、更强大的组件开发方式。本文将带你深入了解这一革命性的特性。

🚀 什么是组合式API?
组合式API是Vue 3引入的一套新的API,它允许我们以函数的方式组织组件逻辑,相比选项式API具有更好的逻辑复用性和类型推导能力。
核心优势
- 更好的逻辑复用: 通过组合函数实现逻辑复用
- 更好的类型推导: 对TypeScript更友好
- 更灵活的代码组织: 按功能而非选项组织代码
- 更小的打包体积: 更好的tree-shaking支持
📚 基础概念
setup函数
setup是组合式API的入口点:
import { ref, reactive, computed, onMounted } from 'vue'
export default {
setup() {
// 响应式数据
const count = ref(0)
const user = reactive({
name: 'Vue',
age: 3
})
// 计算属性
const doubleCount = computed(() => count.value * 2)
// 方法
const increment = () => {
count.value++
}
// 生命周期
onMounted(() => {
console.log('组件已挂载')
})
// 返回模板需要的数据和方法
return {
count,
user,
doubleCount,
increment
}
}
}
响应式API
ref vs reactive
import { ref, reactive } from 'vue'
// ref: 用于基本类型和对象
const count = ref(0)
const message = ref('Hello Vue3')
// reactive: 用于对象和数组
const state = reactive({
user: {
name: 'Alice',
email: 'alice@example.com'
},
todos: []
})
// 访问ref需要.value
console.log(count.value) // 0
count.value++
// reactive直接访问
console.log(state.user.name) // Alice
state.user.name = 'Bob'
🛠️ 高级应用
自定义组合函数
创建可复用的逻辑:
// composables/useCounter.js
import { ref, computed } from 'vue'
export function useCounter(initialValue = 0) {
const count = ref(initialValue)
const doubleCount = computed(() => count.value * 2)
const increment = () => count.value++
const decrement = () => count.value--
const reset = () => count.value = initialValue
return {
count,
doubleCount,
increment,
decrement,
reset
}
}
使用自定义组合函数:
import { useCounter } from '@/composables/useCounter'
export default {
setup() {
const { count, doubleCount, increment, decrement, reset } = useCounter(10)
return {
count,
doubleCount,
increment,
decrement,
reset
}
}
}
生命周期钩子
import {
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted
} from 'vue'
export default {
setup() {
onBeforeMount(() => {
console.log('组件即将挂载')
})
onMounted(() => {
console.log('组件已挂载')
})
onBeforeUpdate(() => {
console.log('组件即将更新')
})
onUpdated(() => {
console.log('组件已更新')
})
onBeforeUnmount(() => {
console.log('组件即将卸载')
})
onUnmounted(() => {
console.log('组件已卸载')
})
}
}
🎯 实战案例:待办事项应用
让我们创建一个完整的待办事项应用:
// TodoApp.vue
<template>
<div class="todo-app">
<h1>待办事项</h1>
<form @submit.prevent="addTodo">
<input
v-model="newTodo"
placeholder="添加新任务..."
required
>
<button type="submit">添加</button>
</form>
<div class="filters">
<button
v-for="filter in filters"
:key="filter"
:class="{ active: currentFilter === filter }"
@click="currentFilter = filter"
>
{{ filter }}
</button>
</div>
<ul class="todo-list">
<li
v-for="todo in filteredTodos"
:key="todo.id"
:class="{ completed: todo.completed }"
>
<input
type="checkbox"
v-model="todo.completed"
>
<span>{{ todo.text }}</span>
<button @click="removeTodo(todo.id)">删除</button>
</li>
</ul>
<div class="stats">
<p>总计: {{ todos.length }}</p>
<p>已完成: {{ completedCount }}</p>
<p>未完成: {{ remainingCount }}</p>
</div>
</div>
</template>
<script>
import { useTodos } from '@/composables/useTodos'
export default {
name: 'TodoApp',
setup() {
const {
todos,
newTodo,
currentFilter,
filters,
filteredTodos,
completedCount,
remainingCount,
addTodo,
removeTodo
} = useTodos()
return {
todos,
newTodo,
currentFilter,
filters,
filteredTodos,
completedCount,
remainingCount,
addTodo,
removeTodo
}
}
}
</script>
组合函数实现:
// composables/useTodos.js
import { ref, reactive, computed } from 'vue'
export function useTodos() {
const todos = ref([])
const newTodo = ref('')
const currentFilter = ref('全部')
const filters = ['全部', '未完成', '已完成']
// 计算属性
const filteredTodos = computed(() => {
switch (currentFilter.value) {
case '未完成':
return todos.value.filter(todo => !todo.completed)
case '已完成':
return todos.value.filter(todo => todo.completed)
default:
return todos.value
}
})
const completedCount = computed(() =>
todos.value.filter(todo => todo.completed).length
)
const remainingCount = computed(() =>
todos.value.filter(todo => !todo.completed).length
)
// 方法
const addTodo = () => {
if (newTodo.value.trim()) {
todos.value.push({
id: Date.now(),
text: newTodo.value.trim(),
completed: false
})
newTodo.value = ''
}
}
const removeTodo = (id) => {
const index = todos.value.findIndex(todo => todo.id === id)
if (index > -1) {
todos.value.splice(index, 1)
}
}
return {
todos,
newTodo,
currentFilter,
filters,
filteredTodos,
completedCount,
remainingCount,
addTodo,
removeTodo
}
}
📊 性能优化
使用shallowRef和shallowReactive
import { shallowRef, shallowReactive } from 'vue'
// 只有根级别的属性是响应式的
const state = shallowReactive({
user: { name: 'Alice' }, // 这个对象内部不是响应式的
count: 0 // 这个是响应式的
})
// 只有.value的赋值是响应式的
const data = shallowRef({
items: [1, 2, 3] // 数组内部的变化不会触发更新
})
使用readonly
import { reactive, readonly } from 'vue'
const state = reactive({
count: 0
})
const readonlyState = readonly(state)
// 这会在开发环境发出警告
readonlyState.count++ // 警告: 无法修改只读属性
🔧 调试技巧
使用watchEffect进行调试
import { watchEffect } from 'vue'
export default {
setup() {
const count = ref(0)
// 调试响应式数据变化
watchEffect(() => {
console.log('count changed:', count.value)
})
return { count }
}
}
📝 最佳实践
合理使用ref和reactive
- 基本类型使用ref
- 对象和数组使用reactive
- 需要重新赋值的对象使用ref
组合函数命名
- 以use开头
- 描述性命名
- 返回对象解构
逻辑分离
- 按功能组织代码
- 提取可复用逻辑
- 保持setup函数简洁
类型安全
- 使用TypeScript
- 定义明确的接口
- 利用类型推导
🎉 总结
Vue 3的组合式API为我们提供了更强大、更灵活的开发方式。通过合理使用这些API,我们可以:
- 编写更可维护的代码
- 实现更好的逻辑复用
- 获得更好的TypeScript支持
- 构建更高性能的应用
开始在你的项目中使用组合式API吧,体验Vue 3带来的开发乐趣!
💡 提示: 组合式API并不是要完全替代选项式API,你可以在同一个项目中混合使用两种风格。选择最适合你和团队的方式!