Appearance
Vue 组合式API
本文介绍Vue 3引入的组合式API(Composition API),包括其设计理念、核心功能以及与选项式API的对比,帮助开发者更好地组织和复用组件逻辑。
什么是组合式API?
组合式API是Vue 3提供的一套新的API,旨在解决大型组件中的逻辑组织和复用问题。与选项式API(Options API)将代码按照data、methods、computed等选项进行组织不同,组合式API允许开发者根据逻辑功能将代码组织成函数,提高代码的可维护性和复用性。
组合式API的优势
- 更好的代码组织:相关逻辑可以被组合在一起,而不是分散在不同的选项中
- 更灵活的逻辑复用:通过自定义组合函数(Composables)复用逻辑,替代了选项式API中的mixin
- 更好的类型支持:与TypeScript结合更紧密,提供更好的类型推断
- 更小的生产包体积:通过tree-shaking减少未使用代码
setup函数
setup函数是组合式API的入口点,在组件创建之前执行,用于设置组件的状态、方法等。
基本用法
javascript
import { ref } from 'vue'
export default {
setup() {
// 声明响应式状态
const count = ref(0)
// 声明方法
const increment = () => {
count.value++
}
// 返回值会暴露给模板和组件实例
return {
count,
increment
}
}
}在模板中使用
html
<template>
<div>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
</div>
</template>setup的参数
setup函数接收两个参数:props和context。
javascript
export default {
props: {
title: {
type: String,
required: true
}
},
setup(props, context) {
// props是响应式的,不能直接解构
console.log(props.title)
// context是一个普通对象,可以解构
const { attrs, slots, emit, expose } = context
// 向父组件暴露方法
expose({
someMethod() {
/* ... */
}
})
return {}
}
}响应式API
组合式API提供了一系列创建响应式数据的函数,替代了选项式API中的data选项。
ref
ref用于创建可以持有任何类型值的响应式ref对象。
javascript
import { ref } from 'vue'
// 创建ref
const count = ref(0)
const message = ref('Hello')
const isActive = ref(true)
// 访问ref的值
console.log(count.value) // 0
// 修改ref的值
count.value++
console.log(count.value) // 1reactive
reactive用于创建对象类型的响应式数据。
javascript
import { reactive } from 'vue'
// 创建响应式对象
const user = reactive({
name: 'John',
age: 30
})
// 访问和修改属性
console.log(user.name) // John
user.age = 31响应式转换规则
- ref用于基本类型数据(String、Number、Boolean等)
- reactive用于对象类型数据(Object、Array等)
- ref对象在模板中使用时会自动解包,不需要使用.value
- 可以使用toRefs将reactive对象转换为多个ref
javascript
import { reactive, toRefs } from 'vue'
const user = reactive({
name: 'John',
age: 30
})
// 将reactive对象转换为ref
const { name, age } = toRefs(user)
// 现在可以单独使用这些ref
console.log(name.value) // John计算属性与侦听器
computed
computed函数用于创建计算属性,与选项式API中的computed选项功能相同。
javascript
import { ref, computed } from 'vue'
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
console.log(doubleCount.value) // 0
count.value = 1
console.log(doubleCount.value) // 2watch
watch函数用于侦听数据变化,与选项式API中的watch选项功能相同。
javascript
import { ref, watch } from 'vue'
const count = ref(0)
// 侦听ref
watch(count, (newValue, oldValue) => {
console.log(`count changed from ${oldValue} to ${newValue}`)
})
// 侦听多个源
watch([count, () => user.age], ([newCount, newAge], [oldCount, oldAge]) => {
/* ... */
})
// 深度侦听
watch(
() => user,
(newUser, oldUser) => {
/* ... */
},
{ deep: true }
)watchEffect
watchEffect是一个简化版的watch,它会自动收集依赖。
javascript
import { ref, watchEffect } from 'vue'
const count = ref(0)
const stop = watchEffect(() => {
console.log(`count is ${count.value}`)
})
// 停止侦听
stop()生命周期钩子
组合式API提供了一系列生命周期钩子函数,以函数调用的方式使用,替代了选项式API中的生命周期选项。
javascript
import { onMounted, onUpdated, onUnmounted } from 'vue'
export default {
setup() {
onMounted(() => {
console.log('Component mounted!')
})
onUpdated(() => {
console.log('Component updated!')
})
onUnmounted(() => {
console.log('Component unmounted!')
})
}
}常用生命周期钩子
- onBeforeMount:组件挂载前调用
- onMounted:组件挂载后调用
- onBeforeUpdate:组件更新前调用
- onUpdated:组件更新后调用
- onBeforeUnmount:组件卸载前调用
- onUnmounted:组件卸载后调用
- onErrorCaptured:捕获子组件错误时调用
- onActivated:keep-alive组件激活时调用
- onDeactivated:keep-alive组件停用时调用
依赖注入
provide和inject函数用于组件间的依赖注入,替代了选项式API中的provide和inject选项。
父组件提供数据
javascript
import { provide, ref } from 'vue'
export default {
setup() {
const theme = ref('light')
const changeTheme = () => {
theme.value = theme.value === 'light' ? 'dark' : 'light'
}
// 提供数据和方法
provide('theme', theme)
provide('changeTheme', changeTheme)
}
}子组件注入数据
javascript
import { inject } from 'vue'
export default {
setup() {
// 注入数据和方法
const theme = inject('theme')
const changeTheme = inject('changeTheme')
return {
theme,
changeTheme
}
}
}组合函数(Composables)
组合函数是组合式API的核心思想,用于封装和复用组件逻辑。组合函数通常命名以use开头。
创建组合函数
javascript
// 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
}
}使用组合函数
javascript
// CounterComponent.vue
import { useCounter } from './useCounter'
export default {
setup() {
const { count, increment, decrement } = useCounter(10)
return {
count,
increment,
decrement
}
}
}与选项式API的对比
选项式API的局限性
- 逻辑关注点分散:相关逻辑分散在不同选项中
- 逻辑复用困难:mixin存在命名冲突、来源不清晰等问题
- 类型支持有限:对TypeScript支持不够友好
组合式API的改进
- 逻辑聚合:相关逻辑可以组织在一起
- 明确的逻辑复用:通过组合函数显式复用逻辑
- 更好的类型支持:与TypeScript无缝集成
- 更灵活的代码组织:可以根据功能拆分代码
如何选择
- 小型组件:选项式API可能更简洁
- 大型组件:组合式API更有利于维护
- 逻辑复用需求高:组合式API的组合函数更适合
- 新项目:推荐使用组合式API
- 现有项目:可以渐进式采用组合式API
组合式API的最佳实践
提取组合函数
将组件中的逻辑提取为独立的组合函数,提高复用性。
按功能组织代码
将相关的状态和方法组织在一起,而不是按选项类型组织。
使用TypeScript
组合式API与TypeScript结合使用,可以获得更好的类型检查和自动补全。
避免过度拆分
不要为了拆分而拆分,适度的逻辑聚合更有利于维护。
使用命名规范
组合函数以use开头,如useCounter、useApi等,便于识别。
总结
组合式API为Vue开发者提供了一种新的代码组织方式,特别适合处理复杂组件中的逻辑。通过setup函数、响应式API、生命周期钩子和组合函数,开发者可以编写出更具可维护性和复用性的代码。组合式API不是对选项式API的替代,而是提供了一种新的选择,开发者可以根据项目需求和个人偏好选择合适的API风格。