Vue3 的组合式 API(Composition API)是 Vue 近几年最重要的演进。它解决了 Options API 在大型组件中"逻辑按选项分散、难以聚合"的痛点,让相关逻辑可以集中组织、抽离复用。本文覆盖 setup、响应式原理、计算属性、侦听器与生命周期,并演示如何抽离可复用逻辑。
一、setup:组合式 API 的入口
setup 是组合式 API 的入口函数,在组件创建之初执行,此时 props 已解析但尚未挂载 this。<script setup> 是它的语法糖,让代码更简洁,是 Vue3 的推荐写法。
<script setup>
import { ref, computed } from 'vue'
// 响应式状态
const count = ref(0)
const double = computed(() => count.value * 2)
function add() {
count.value++
}
</script>
<template>
<button @click="add">{{ count }} × 2 = {{ double }}</button>
</template>
在 <script setup> 中,顶层声明的变量、函数会自动暴露给模板,无需 return,导入的组件也可直接使用。
二、ref 与 reactive:响应式双兄弟
ref 用于基本类型(也可包对象),通过 .value 访问;reactive 用于对象/数组,返回代理对象,直接访问属性即可。
import { ref, reactive } from 'vue'
// ref:基本类型推荐
const title = ref('多彩编程')
function setTitle(v) { title.value = v }
// reactive:对象/数组推荐
const user = reactive({
name: '小明',
age: 18,
hobbies: ['编程', '阅读']
})
user.age++ // 直接修改
user.hobbies.push('音乐')
选择建议:基本类型用 ref,对象/集合用 reactive。解构 reactive 会丢失响应式,需要用 toRefs 保持;ref 解构则正常。
三、computed:派生状态
计算属性基于响应式依赖缓存,只有依赖变化时才重新计算,适合派生数据。
import { ref, computed } from 'vue'
const price = ref(100)
const qty = ref(3)
// 只读计算属性
const total = computed(() => price.value * qty.value)
// 可写计算属性(get/set)
const discount = computed({
get: () => price.value * 0.8,
set: (v) => { price.value = v / 0.8 }
})
四、watch 与 watchEffect:侦听变化
watch 显式指定侦听源,变化时执行回调,可拿到新旧值;watchEffect 自动收集回调内的依赖,立即执行一次,适合"副作用跟随依赖"的场景。
import { ref, watch, watchEffect } from 'vue'
const keyword = ref('')
// watch:明确侦听 keyword,变化时触发
watch(keyword, (newVal, oldVal) => {
console.log(`${oldVal} -> ${newVal}`)
fetchSuggest(newVal)
}, { immediate: false, deep: false })
// watchEffect:自动追踪回调内用到的响应式数据
watchEffect(() => {
// 用到 keyword.value,自动建立依赖
document.title = `搜索:${keyword.value}`
})
immediate: true让 watch 立即执行一次。deep: true深度侦听对象内部变化(性能开销大,慎用)。- 侦听多个源:
watch([a, b], ([na, nb]) => {})。
五、生命周期:onMounted 等
组合式 API 把生命周期钩子改成函数形式,需在 setup 同步注册。
import { onMounted, onUpdated, onUnmounted } from 'vue'
onMounted(() => {
console.log('DOM 已挂载,可访问 ref')
window.addEventListener('resize', onResize)
})
onUnmounted(() => {
// 组件销毁时清理,避免内存泄漏
window.removeEventListener('resize', onResize)
})
六、实战:抽离可复用逻辑(Composable)
组合式 API 最大的价值在于把逻辑抽成独立函数复用。下面封装一个鼠标位置追踪逻辑,任何组件都能用。
// composables/useMousePosition.js
import { ref, onMounted, onUnmounted } from 'vue'
export function useMousePosition() {
const x = ref(0)
const y = ref(0)
function update(e) {
x.value = e.pageX
y.value = e.pageY
}
onMounted(() => window.addEventListener('mousemove', update))
onUnmounted(() => window.removeEventListener('mousemove', update))
return { x, y }
}
// 组件中使用
// <script setup>
import { useMousePosition } from '@/composables/useMousePosition'
const { x, y } = useMousePosition()
// </script>
// <template>鼠标:{{ x }}, {{ y }}</template>
相比 Vue2 的 mixin,这种 Composable 模式有三大优势:
- 来源清晰:逻辑来源一目了然,不再有 mixin 的隐式注入冲突。
- 类型友好:配合 TypeScript 可获得完整类型推断。
- 按需引入:像引入普通函数一样组合,灵活度极高。
掌握组合式 API 的关键,是建立"按功能而非按选项组织代码"的思维。当你在写一个复杂表单时,把校验逻辑、提交逻辑、字段联动各自抽成 Composable,组件会变得异常清爽。这正是组合式 API 带来的工程价值。