Vue3 组合式 API 完全指南

小飞兽 Vue.js 300 次阅读 2026-05-27

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,对象/数组用 reactiveref([...])。注意 reactive 存在解构丢失响应式的问题,需要使用 toRefs 转换。

Q2:<code>watch</code> 和 <code>watchEffect</code> 如何选择?

watch 需要显式指定监听目标,只有当目标变化时才执行回调,适合执行有明确副作用边界的场景(如请求接口)。watchEffect 自动收集依赖,初始化时立即执行,适合简单的同步日志打印等场景。注意 watchEffect 回调中访问的响应式数据都会被追踪为依赖。

Q3:组合式 API 的生命周期钩子与选项式如何对应?

onMounted(挂载后)对应 mountedonUpdated(更新后)对应 updatedonUnmounted(卸载前)对应 beforeUnmount。组合式钩子需要在 setup<script setup> 中调用,允许多次注册(同一钩子可注册多个回调),而选项式每个生命周期只能有一个处理函数。

延伸阅读

  • <a href="#">Vue3 响应式系统深度解析: ref vs reactive</a> —— 深入理解两种响应式数据创建方式的底层原理与适用场景
  • <a href="#">Vue3 计算属性和监听器完全指南</a> —— 掌握 computed、watch、watchEffect 的进阶用法
  • <a href="#">Vue3 生命周期钩子详解</a> —— 图解 Vue3 所有生命周期阶段与钩子函数