在Vue3从发布到今天,组合式API已成为现代前端开发的标杆设计模式。本文通过真实项目场景,深度解析组合式API的核心特性,配以完整代码示例,助你彻底掌握企业级Vue应用开发精髓。
前言
一、为什么组合式API是Vue3的革命性升级?
1.1 选项式API的痛点
- 代码碎片化:数据在
data
,方法在methods
,计算属性在computed
- 逻辑耦合:1000行组件中找关联逻辑如同”大海捞针”
- 复用困难:Mixins存在命名冲突和来源不清晰问题
// 传统Options API(用户管理组件)
export default {
data() {
return {
users: [],
filters: {},
pagination: {}
}
},
methods: {
fetchUsers() {/* 30行代码 */},
deleteUser() {/* 20行代码 */},
exportReport() {/* 15行代码 */}
},
computed: {
filteredUsers() {/* 依赖users和filters */}
},
watch: {
filters: {/* 复杂监听逻辑 */}
}}
1.2 组合式API的三大优势
- 逻辑聚合:按功能而非选项组织代码
- 完美复用:函数式封装实现”即插即用”
- 类型支持:天然适配TypeScript
// 使用组合式API重构
import { useUserFetch } from './composables/userFetch'
import { useTableFilter } from './composables/tableFilter'
export default {
setup() {
const { users, fetchUsers } = useUserFetch()
const { filteredData, filters } = useTableFilter(users)
return { users, filteredData, filters, fetchUsers } }
}
二、组合式API核心机制深度剖析(附完整代码)
2.1 setup函数:新世界的入口
<template>
<button @click="increment">8</button>
</template>
<script setup>
// 编译器宏语法糖(无需显式返回)
import { ref } from 'vue'
const count = ref(0)
const increment = () => count.value++
</script>
关键细节:
- 执行时机:在
beforeCreate
之前 - 参数解析:
props
是响应式的,不要解构! - Context对象:包含
attrs
/slots
/emit
等
2.2 ref() vs reactive() 选择指南
场景 | 推荐方案 | 原因 |
---|---|---|
基础类型数据 | ref() | 自动解包,模版使用更方便 |
复杂对象/数组 | reactive() | 深层响应式,性能更优 |
第三方类实例 | reactive() | 保持原型链方法 |
跨组件状态共享 | ref() + provide/inject | 响应式追踪更可靠 |
ref的底层原理
function myRef(value) {
return {
get value() { track(this, 'value') // 依赖收集
return value
},
set value(newVal) {
value = newVal
trigger(this, 'value') // 触发更新
}
}
}
三、高级实战技巧
3.1 通用数据请求封装
// useFetch.js
export const useFetch = (url) => {
const data = ref(null)
const error = ref(null)
const loading = ref(false)
const fetchData = async () => {
try {
loading.value = true
const response = await axios.get(url)
data.value = response.data
} catch (err) {
error.value = err
} finally {
loading.value = false
}
}
onMounted(fetchData)
return { data, error, loading, retry: fetchData }}
// 组件中使用
const { data: posts } = useFetch('/api/posts')
3.2 防抖搜索实战
// useDebounceSearch.js
export function useDebounceSearch(callback, delay = 500) {
const searchQuery = ref('')
let timeoutId = null
watch(searchQuery, (newVal) => {
clearTimeout(timeoutId)
timeoutId = setTimeout(() => callback(newVal), delay)
})
return { searchQuery }
}
四、性能优化最佳实践
4.1 计算属性缓存策略
const filteredList = computed(() => { // 通过闭包缓存中间结果
const cache = {}
return (filterKey) => {
if(cache[filterKey]) return cache[filterKey]
return cache[filterKey] = heavyCompute()
}
})
4.2 watchEffect() 的高级用法
// 立即执行+自动追踪依赖
watchEffect(() => {
const data = fetchData(params.value)
console.log('依赖自动追踪:', data)
}, {
flush: 'post', // DOM更新后执行
onTrack(e) { /* 调试追踪 */ }
})
4.3 内存泄漏防范
// 定时器示例
onMounted(() => {
const timer = setInterval(() => {...}, 1000)
onUnmounted(() => clearInterval(timer))
})
五、TypeScript终极适配方案
interface User { id: number name: string} // 带类型的ref
const user = ref<User>({ id: 1, name: 'John' }) // 组合函数类型定义
export function useCounter(): { count: Ref<number> increment: () => void} { // 实现...}