首页 / Nuxt 4 入门教程 / 组合式 API

Nuxt 4 入门教程

组合式 API

本教程共 50 篇 · 第 11 篇 · 更新于 2026-08-08 · 约 7 分钟阅读

NuxtNuxt4Vue3组合式APIrefreactivecomputedwatch

本节目标:熟练使用 Vue 3 组合式 API 的四个基础:refreactivecomputedwatch,知道各自适用场景,能在 <script setup> 里正确读写。

上一章说了「响应式」是 Vue 的灵魂。这章就把实现响应式的工具交给你——组合式 API(Composition API)。在 Nuxt 里你几乎天天和它打交道。四个最常用:refreactivecomputedwatch

11-1

ref() 用来把一个值(数字、字符串、对象、数组都行)包成「响应式容器」。它返回的是一个对象,真正的值存在 .value 上。

<script setup lang="ts">
const count = ref(0)

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

<template>
  <p>计数:{{ count }}</p>
  <button @click="increment">加一</button>
</template>

注意两个地方的区别:

  • <script>访问或改值,要写 count.value
  • <template>直接用 count,Vue 会自动帮你补上 .value(这叫自动解包)。
Tip

不确定该用 ref 还是 reactive?记一条:基本类型(数字、字符串、布尔)用 ref;对象/数组用 ref 也完全没问题。新手统一用 ref 最省心,不用纠结。

11-2

reactive() 专门给对象或数组加响应式,好处是不用 .value,直接点属性访问:

<script setup lang="ts">
const user = reactive({
  name: '小明',
  age: 18,
})

function grow() {
  user.age++
}
</script>

<template>
  <p>{{ user.name }} 今年 {{ user.age }} 岁</p>
  <button @click="grow">涨一岁</button>
</template>

但有坑:reactive 整个对象不能被整体替换,否则响应式会断。比如 user = { ... } 这种重新赋值会让绑定失效。所以处理「可能整体替换」的数据,还是用 ref 更稳。

Warning

别把 reactive 对象解构成多个独立变量(如 const { name } = user),解构出来的值会失去响应性。要用就整体用 user.xxx

11-3

computed() 接收一个函数,返回一个响应式结果,而且它会「聪明地」记住自己依赖了谁:只有依赖变,它才重算;依赖没变,多次访问直接返回缓存值。

经典场景:两个输入框的值相加。

<script setup lang="ts">
const a = ref(1)
const b = ref(2)

// result 始终等于 a + b,a 或 b 一变它就自动更新
const result = computed(() => a.value + b.value)
</script>

<template>
  <p>{{ a }} + {{ b }} = {{ result }}</p>
</template>

computed 默认是只读的(你不该手动给 result.value 赋值)。如果需要可写的计算属性,可以传一个带 get/set 的对象,但初学很少用到。

Note

computed 和「方法(函数)」都能算出值,但区别在性能:方法每次渲染都重跑;computed 有缓存,依赖不变就不重算。频繁依赖派生数据的,用 computed 更合适。

11-4

computed 适合「算出一个新值」,watch() 适合「值变了,去干一件事」(这叫副作用,side effect)。比如:监听登录失败次数,超过阈值就禁用按钮;或监听某个值,变化时发请求。

<script setup lang="ts">
const count = ref(0)

watch(count, (newValue, oldValue) => {
  console.log(`count 从 ${oldValue} 变成了 ${newValue}`)
})
</script>

第一个参数是「要监听什么」,第二个是「变了怎么处理」的回调,回调能拿到新旧两个值。

想同时监听多个源,传数组即可:

watch([a, b], ([newA, newB]) => {
  // a 或 b 变化都会触发
})
Tip

watch 默认是「懒」的——只在变化后触发,不会立刻跑一次。如果你想「一开始就跑一次、之后每次变化也跑」,加第三个参数 { immediate: true }。需要深度监听嵌套对象时用 { deep: true }

11-5

真实组件里,这四个通常一起出现:ref/reactive 存状态,computed 派生展示值,watch 响应变化做额外动作。

<script setup lang="ts">
const price = ref(100)
const quantity = ref(2)

// 派生:总价
const total = computed(() => price.value * quantity.value)

// 副作用:总价变化时记一笔日志
watch(total, (val) => {
  console.log('总价更新为', val)
})
</script>

<template>
  <p>单价 {{ price }},数量 {{ quantity }},合计 {{ total }}</p>
</template>

11-6

组合式 API 太好用,新手容易什么都包成响应式。但无意义的 computed/watch 多了,一个改动会触发一串重算,调试时很难追溯「到底谁动了」。

Warning

写响应式时反过来问:「这个值真的会变吗?变了真的需要触发更新吗?」不变、或能靠普通函数解决的数据,就用普通变量/函数,别强加响应式。保持克制,项目大了才稳。

11-7

如果你听过 Vue 老式的「选项式 API」(data()methodscomputed 分开写),组合式 API 的区别在于:按「逻辑关注点」组织代码,而不是按「选项类型」

选项式里,一个「计数器」功能的相关代码会被拆到 datamethods 好几处;组合式 API 里,你可以把「状态 + 派生 + 副作用」紧挨着写在一起,读一段就能看懂一个功能。在 Nuxt 里,所有 .vue 组件的 <script setup> 天然就是组合式风格。

Tip

心智模型一句话:组合式 API 就是把「关于同一件事的状态和逻辑」打包成一小块代码。组件就是由这样几小块拼起来的。

11-8

当一段响应式逻辑在多个组件都要用时,别复制粘贴——把它抽成一个组合式函数,放进 app/composables/。Nuxt 会自动导入它,任何组件直接调用。

比如一个「鼠标坐标」逻辑:

// app/composables/useMouse.ts
export function useMouse() {
  const x = ref(0)
  const y = ref(0)
  function update(e: MouseEvent) {
    x.value = e.clientX
    y.value = e.clientY
  }
  onMounted(() => window.addEventListener('mousemove', update))
  onUnmounted(() => window.removeEventListener('mousemove', update))
  return { x, y }
}

组件里:

<script setup lang="ts">
const { x, y } = useMouse()
</script>

约定俗成:组合式函数以 use 开头命名(如 useFetchuseMouse),放在 composables/ 目录。Nuxt 会把它变成全局可用,不用手写 import——这正是「约定优于配置」再一次生效。

Note

组合式函数里也能用 refcomputedwatch,以及生命周期钩子(onMounted 等)。它本质就是一段「带响应式状态的函数」,把复用逻辑从组件里解放出来,是 Nuxt 项目里复用代码的主力方式。

11-9

ref 包单个值(脚本里用 .value,模板里自动解包);reactive 包对象但别整体替换;computed 派生带缓存的值;watch 在变化后做副作用。四个配合,几乎覆盖所有组件内的状态逻辑。下一章讲组件之间怎么用 props 和插槽通信。

11-9 组合式 API 的测试优势

组合式 API 相比选项式 API 还有一个常被忽略的优势:更易于单元测试。因为逻辑被封装在函数里,你可以直接导入并调用这些函数,传入模拟参数,验证返回值。不需要挂载整个组件就能测试核心业务逻辑。

在 Nuxt 项目里,composables/ 目录下的组合式函数可以独立编写测试。配合 Vitest(Nuxt 默认测试框架),你可以快速验证数据获取、状态管理、计算逻辑是否正确。这种测试方式比组件级测试更快、更稳定。

编写组合式函数时,建议保持每个函数的职责单一。一个函数只做一件事,测试起来简单,复用起来也方便。如果一个组合式函数超过五十行,通常意味着它承担了太多职责,值得拆分。

11-10 组合式 API 与性能优化

组合式 API 在性能方面也有优势。由于相关逻辑可以组织在一起,构建工具能更好地做代码分割和树摇(tree-shaking)。没有被使用的组合式函数会在构建时被自动移除,不会增加最终产物的体积。

在 Nuxt 里,组合式函数的自动导入也经过了优化。框架在构建时分析哪些组合式函数被实际使用了,只导入用到的部分。这意味着你可以放心地在 composables/ 目录下放很多工具函数,不用担心没用到的那些会影响包体积。