Vue3 组合式 API 完全指南
Vue3 组合式 API 完全指南
概述
Vue3 组合式 API(Composition API)是 Vue3 引入的全新编程范式,它将相关逻辑组织在一起,而不是按选项类型(data、methods、computed)分散处理。相比传统的选项式 API,组合式 API 在处理复杂组件逻辑、代码复用(Composables)方面具有显著优势,是现代 Vue 开发的必掌握核心特性。
为什么需要组合式 API
当组件逻辑逐渐复杂时,按选项组织的代码会出现"横切关注点"问题:同一个逻辑功能的代码被拆分到 data、methods、computed、watch 四个角落,后期维护困难。组合式 API 允许你按功能而非选项类型来组织代码,使大型项目的代码更易理解和测试。
基础语法
组合式 API 通过 <script setup> 语法糖在 Vue3 中使用,所有 API 从 vue 包导入:
import { ref, reactive, computed, watch, onMounted } from 'vue'
- <code>ref</code>:创建响应式引用,用于基本类型(字符串、数字、布尔等)
- <code>reactive</code>:创建深度响应式对象,用于复杂类型(对象、数组)
- <code>computed</code>:创建计算属性,基于响应式数据自动推导
- <code>watch</code> / <code>watchEffect</code>:监听数据变化执行副作用
- <code>onMounted</code> 等:生命周期钩子
完整代码示例
以下是一个完整的用户资料管理组件,演示组合式 API 的核心用法:
<script setup>
import { ref, reactive, computed, watch, onMounted, onUnmounted } from 'vue'
// —— 1. 基础响应式数据 ——
// ref 用于基本类型,访问时需要 .value(模板中自动解包)
const username = ref('林小鸣')
const age = ref(28)
const isEditing = ref(false)
// reactive 用于对象/数组,访问时直接使用属性名
const profile = reactive({
city: '杭州',
bio: '前端开发工程师',
skills: ['Vue', 'React', 'TypeScript'],
settings: {
theme: 'dark',
language: 'zh-CN'
}
})
// —— 2. 计算属性:根据现有数据派生新值 ——
// 只有当依赖的响应式数据变化时,才会重新计算
const displayName = computed(() => {
return `${username.value}(${age.value}岁)`
})
// 检测技能列表是否包含某技能
const hasVueSkill = computed(() => {
return profile.skills.includes('Vue')
})
// —— 3. 方法:普通函数处理逻辑 ——
function toggleEdit() {
isEditing.value = !isEditing.value
}
function updateProfile(field, value) {
if (field in profile.settings) {
profile.settings[field] = value
}
}
function addSkill(skill) {
if (!profile.skills.includes(skill)) {
profile.skills.push(skill)
}
}
// —— 4. 监听器:响应数据变化执行副作用 ——
// watch 精确监听指定数据源
watch(username, (newVal, oldVal) => {
console.log(`用户名从 ${oldVal} 变为 ${newVal}`)
})
// watchEffect 自动追踪依赖,执行前会立即运行一次
watchEffect(() => {
console.log(`当前主题:${profile.settings.theme}`)
})
// —— 5. 生命周期钩子 ——
onMounted(() => {
console.log('组件已挂载,用户名:', username.value)
window.addEventListener('resize', handleResize)
})
onUnmounted(() => {
console.log('组件即将卸载,清理资源...')
window.removeEventListener('resize', handleResize)
})
function handleResize() {
console.log('窗口大小改变')
}
</script>
<template>
<div class="user-profile">
<h2>{{ displayName }}</h2>
<p>城市:{{ profile.city }}</p>
<p>简介:{{ profile.bio }}</p>
<p>是否掌握 Vue:{{ hasVueSkill ? '是' : '否' }}</p>
<button @click="toggleEdit">
{{ isEditing ? '取消编辑' : '编辑资料' }}
</button>
<div v-if="isEditing">
<input v-model="username" placeholder="用户名" />
<input v-model="age" type="number" placeholder="年龄" />
<input v-model="profile.settings.theme" placeholder="主题" />
</div>
<ul>
<li v-for="skill in profile.skills" :key="skill">{{ skill }}</li>
</ul>
</div>
</template>
<style scoped>
.user-profile {
padding: 1rem;
border-radius: 8px;
background: var(--bg-color, #f5f5f5);
}
button { margin-top: 0.5rem; }
</style>
运行效果说明
运行上述组件后,页面显示用户的基本信息和技能列表。点击"编辑资料"按钮后,输入框出现,修改用户名或年龄时,displayName 计算属性会自动更新(无需手动调用)。watch 监听器会在控制台打印用户名变化日志。组件卸载时,onUnmounted 中的事件监听清理逻辑会执行,防止内存泄漏。
常见问题
Q1:ref 和 reactive 有什么区别?该用哪个?
ref 接收任意类型值,返回一个具有 .value 属性的响应式对象;reactive 只接收对象/数组,返回原始对象的 Proxy 代理。建议:基本类型(string/number/boolean)用 ref,对象/数组用 reactive 或 ref([...])。注意 reactive 存在解构丢失响应式的问题,需要使用 toRefs 转换。
Q2:<code>watch</code> 和 <code>watchEffect</code> 如何选择?
watch 需要显式指定监听目标,只有当目标变化时才执行回调,适合执行有明确副作用边界的场景(如请求接口)。watchEffect 自动收集依赖,初始化时立即执行,适合简单的同步日志打印等场景。注意 watchEffect 回调中访问的响应式数据都会被追踪为依赖。
Q3:组合式 API 的生命周期钩子与选项式如何对应?
onMounted(挂载后)对应 mounted,onUpdated(更新后)对应 updated,onUnmounted(卸载前)对应 beforeUnmount。组合式钩子需要在 setup 或 <script setup> 中调用,允许多次注册(同一钩子可注册多个回调),而选项式每个生命周期只能有一个处理函数。
延伸阅读
- <a href="#">Vue3 响应式系统深度解析: ref vs reactive</a> —— 深入理解两种响应式数据创建方式的底层原理与适用场景
- <a href="#">Vue3 计算属性和监听器完全指南</a> —— 掌握 computed、watch、watchEffect 的进阶用法
- <a href="#">Vue3 生命周期钩子详解</a> —— 图解 Vue3 所有生命周期阶段与钩子函数