Vue 3 组合式 API(Composition API)是 Vue 3 的核心特性之一,它解决了选项式 API 在复杂组件中"逻辑分散、复用困难"的问题。本文通过实际示例带你快速上手。

一、为什么需要组合式 API

在选项式 API 中,一个功能的代码会被拆散到 datamethodscomputedwatch 中。组件一旦复杂,想要定位某个功能的所有代码就要在多个选项之间来回跳转。组合式 API 允许我们按"功能"而不是按"选项类型"组织代码。

二、响应式核心:ref 与 reactive

<script setup>
import { ref, reactive } from 'vue'

// ref 适合基本类型
const count = ref(0)
const username = ref('guest')

// reactive 适合对象
const user = reactive({
  name: '张三',
  age: 25,
})

// 模板中自动解包,无需 .value
// 脚本中操作需要 .value
count.value++

function increment() {
  count.value++
}
</script>

记住一条经验:基本类型用 ref,嵌套对象用 reactive。不过现在也推荐统一用 ref,配合 toRefs 或解构使用更灵活。

三、computed 计算属性

import { ref, computed } from 'vue'

const price = ref(100)
const quantity = ref(2)

// 计算属性有缓存,只有依赖变化时才重算
const total = computed(() => price.value * quantity.value)

// 计算属性默认只读
// 可通过 get/set 实现可写
const totalEditable = computed({
  get: () => price.value * quantity.value,
  set: (val) => { price.value = val / quantity.value },
})

四、watch 侦听器

import { ref, watch } from 'vue'

const keyword = ref('')

// 侦听单个源
watch(keyword, (newVal, oldVal) => {
  console.log('搜索词变化:', oldVal, '→', newVal)
})

// 侦听多个源
watch([keyword, page], ([k, p]) => {
  console.log('条件变化', k, p)
})

// 深度侦听对象
watch(user, (val) => { ... }, { deep: true })

// 立即执行一次
watch(keyword, fn, { immediate: true })

使用 watchEffect 可以自动收集依赖,不需要显式指定侦听的源,适合"副作用跟随状态"的场景。

五、组合式函数:逻辑复用

这是组合式 API 最大的优势。把可复用的逻辑抽成函数:

// usePagination.js
import { ref, computed } from 'vue'

export function usePagination(pageSize = 10) {
  const page = ref(1)
  const total = ref(0)

  const totalPages = computed(() => Math.ceil(total.value / pageSize))
  const canPrev = computed(() => page.value > 1)
  const canNext = computed(() => page.value < totalPages.value)

  function prev() { if (canPrev.value) page.value-- }
  function next() { if (canNext.value) page.value++ }
  function reset() { page.value = 1 }

  return { page, total, totalPages, canPrev, canNext, prev, next, reset }
}

在任意组件中使用:

<script setup>
import { usePagination } from './usePagination'

const { page, total, totalPages, prev, next } = usePagination(20)

// 组件只需要关心业务逻辑
function loadData() {
  // 使用 page.value 请求接口
}
</script>

六、script setup 语法糖

Vue 3.2+ 推荐使用 <script setup>

  • 顶层声明自动暴露给模板,无需 return
  • import 的组件直接可用
  • 支持 defineProps / defineEmits 声明属性与事件
  • 代码更简洁,编译期有性能优化
<script setup>
import { defineProps, defineEmits } from 'vue'

const props = defineProps({ title: String, items: Array })
const emit = defineEmits(['select'])

function handleClick(item) {
  emit('select', item)
}
</script>

小结

组合式 API 的学习曲线平缓,一旦上手就能体会到代码组织与复用的乐趣。建议新项目直接用 <script setup> + 组合式函数,从第一天就保持组件的清晰与可维护。