Vue 3 的 Composition API 是一套函数式 API,用于在组件中更灵活地组织逻辑代码。它解决了 Options API 在大型组件中逻辑分散的问题,提供更好的代码组织和复用能力。
核心 API 概览:
-
响应式 API:
ref():创建基本类型响应式数据reactive():创建对象类型响应式数据computed():创建计算属性watch()/watchEffect():监听响应式变化
-
生命周期钩子:
onMounted()/onUnmounted()等替代mounted/unmounted
-
依赖注入:
provide()/inject()
-
工具函数:
toRefs():保持响应式解构shallowRef()/shallowReactive():浅层响应式
完整示例代码 (.vue 文件)
<script setup>
import {
ref, reactive, computed, watch, watchEffect,
onMounted, onUnmounted, provide, inject,
toRefs, shallowRef, triggerRef, customRef
} from 'vue'
// 1. ref - 基本类型响应式
const counter = ref(0)
const increment = () => counter.value++
// 2. reactive - 对象响应式
const user = reactive({
firstName: 'John',
lastName: 'Doe',
age: 30
})
// 3. computed - 计算属性
const fullName = computed(() => `${user.firstName} ${user.lastName}`)
// 4. watch - 侦听特定值
watch(counter, (newVal, oldVal) => {
console.log(`计数器变化: ${oldVal} → ${newVal}`)
})
// 5. watchEffect - 自动追踪依赖
watchEffect(() => {
console.log(`watchEffect: ${fullName.value} 年龄 ${user.age}`)
})
// 6. 生命周期钩子
onMounted(() => console.log('组件已挂载'))
onUnmounted(() => console.log('组件将卸载'))
// 7. provide/inject - 依赖注入
const appTheme = ref('dark')
provide('theme', appTheme)
// 8. toRefs - 解构保持响应性
const { firstName, lastName } = toRefs(user)
// 9. shallowRef - 浅层响应式
const shallowObj = shallowRef({ deep: { value: 100 } })
const updateShallow = () => {
shallowObj.value.deep.value += 10
triggerRef(shallowObj) // 手动触发更新
}
// 10. customRef - 自定义ref
function useDebouncedRef(value, delay = 500) {
let timeout
return customRef((track, trigger) => ({
get() {
track()
return value
},
set(newValue) {
clearTimeout(timeout)
timeout = setTimeout(() => {
value = newValue
trigger()
}, delay)
}
}))
}
const searchText = useDebouncedRef('')
// 11. 组件逻辑复用示例
function useCounter(initialValue = 0) {
const count = ref(initialValue)
const double = computed(() => count.value * 2)
function reset() {
count.value = initialValue
}
return { count, double, reset }
}
const { count: otherCount, double: otherDouble } = useCounter(10)
// 12. 从inject获取值 (在子组件中演示)
const childTheme = inject('theme', 'light')
</script>
<template>
<div>
<!-- 基础响应式 -->
<div class="section">
<h2>响应式基础</h2>
<button @click="increment">计数: {{ counter }}</button>
<input v-model="user.firstName" placeholder="名字">
<input v-model="user.lastName" placeholder="姓氏">
<p>全名: {{ fullName }}</p>
</div>
<!-- 解构响应式 -->
<div class="section">
<h2>toRefs 解构</h2>
<input v-model="firstName" placeholder="名字 (解构)">
<input v-model="lastName" placeholder="姓氏 (解构)">
</div>
<!-- 浅层响应式 -->
<div class="section">
<h2>浅层响应式</h2>
<button @click="updateShallow">更新深层值: {{ shallowObj.deep.value }}</button>
<p>需要手动 triggerRef 更新视图</p>
</div>
<!-- 自定义Ref -->
<div class="section">
<h2>自定义Ref (防抖)</h2>
<input v-model="searchText" placeholder="输入会500ms防抖">
<p>实时值: {{ searchText }}</p>
</div>
<!-- 逻辑复用 -->
<div class="section">
<h2>逻辑复用</h2>
<p>计数器: {{ otherCount }} × 2 = {{ otherDouble }}</p>
<button @click="otherCount++">增加</button>
</div>
<!-- 依赖注入 -->
<div class="section">
<h2>依赖注入</h2>
<p>当前主题: {{ childTheme }}
<button @click="appTheme = appTheme === 'dark' ? 'light' : 'dark'">
切换主题
</button>
</p>
</div>
</div>
</template>
<style scoped>
.section {
margin: 20px 0;
padding: 15px;
border: 1px solid #eee;
border-radius: 8px;
}
button {
margin: 0 5px;
padding: 5px 10px;
}
input {
margin: 5px;
padding: 5px;
}
</style>
核心 API 使用说明:
-
响应式基础
ref(): 用于基本类型,通过.value访问reactive(): 用于对象类型,直接访问属性- 组合式优于选项式:相关逻辑可以组织在一起
-
计算和侦听
computed(): 基于依赖缓存计算结果watch(): 精确控制侦听源和回调时机watchEffect(): 自动追踪依赖,立即执行
-
生命周期
- 前缀
on+ 生命周期名 (onMounted,onUpdated等) - 可在同一位置组织相关逻辑
- 前缀
-
依赖注入
provide()在祖先组件提供值inject()在后代组件获取值- 避免 props 逐级传递
-
高级响应式
toRefs(): 解构 reactive 对象保持响应性shallowRef(): 只跟踪.value变化customRef(): 创建自定义 ref 实现特殊逻辑
-
代码复用
- 封装自定义 Hook (如示例中的
useCounter) - 类似 React Hooks 的逻辑复用能力
- 封装自定义 Hook (如示例中的
最佳实践:
- 使用
<script setup>简化语法 - 复杂逻辑拆分为独立组合函数
- 相关功能组织在同一代码区域
- 使用 TypeScript 增强类型安全
- 大型项目优先选择 Composition API
Composition API 特别适合复杂组件和逻辑复用场景,通过函数组合的方式使代码更清晰、更易维护,同时保持完整的响应式能力。