都2026年了,还在用Options API?Vue组合式API才是你该掌握的“正确姿势“

很多人学了Vue 3,却还在用Vue 2的思维写代码。今天咱们聊聊,为什么组合式API不是"可选项",而是你进阶的"必修课"。

先别急,咱们讲个故事

想象一下,你刚入职一家公司,领导让你整理办公桌。

Options API的整理方式是这样的:所有的笔放一个抽屉,所有的本子放一个抽屉,所有的充电线放一个抽屉。

听起来很整齐对吧?但当你要处理"写周报"这件事时,你需要从笔的抽屉拿笔,从本子的抽屉拿本子,从充电线的抽屉拿充电器给电脑充电------你得满办公桌翻。

Composition API的整理方式则是:把"写周报"需要的东西放一起,把"画设计稿"需要的东西放一起。做什么事,拿什么包,干净利落。

这就是Vue组合式API的核心思想------按功能组织代码,而不是按类型分类

听起来简单,但这个理念的转变,足以改变你写Vue代码的方式。

Options API到底"哪里不行了"?

咱们先看一个最经典的计数器组件,用Options API写:

go 复制代码
<template>
  <div>
    <p>Count: {{ count }}</p>
    <button @click="increment">+1</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      count: 0
    }
  },
  methods: {
    increment() {
      this.count++
    }
  }
}
</script>

看起来没毛病对吧?简单、清晰、教科书般的写法。

但问题来了------当你的组件不只是一个计数器,而是同时要处理用户信息、搜索过滤、分页加载、表单校验四五个功能时,你的代码会变成这样:

go 复制代码
+------------------+
|    data()        |  ← count、userInfo、searchKey、pageNum、formData 全堆在一起
+------------------+
|    methods       |  ← increment、fetchUser、handleSearch、loadMore、validate 全堆在一起
+------------------+
|    computed      |  ← doubleCount、fullName、filteredList 全堆在一起
+------------------+
|    watch         |  ← 监听count、监听searchKey、监听pageNum 全堆在一起
+------------------+

你发现问题了吗?

"计数器"的逻辑被撕碎了 ------countdata里,incrementmethods里,doubleCountcomputed里,watch countwatch里。你要理解"计数器"这一个功能,得在四个地方来回跳。

组件小的时候还好,一旦超过200行,维护起来就像在一碗面条里找一根特定的面------这就是Options API的"面条式代码"问题。

组合式API:把散落的拼图重新拼好

同样的计数器,用Composition API重写:

go 复制代码
<template>
  <div>
    <p>Count: {{ count }}</p>
    <button @click="increment">+1</button>
  </div>
</template>

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

const count = ref(0)

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

你会发现几个变化:

第一,没有了this 在Options API里,你访问数据要this.count,调用方法要this.increment()。但在组合式API里,一切都是普通的JavaScript变量和函数。没有this指向的困惑,没有"为什么箭头函数里this不对"的经典面试题。

第二,ref是什么? 你可以把ref理解为一个"响应式盒子"。普通的JavaScript变量改了值,Vue不知道;但你把值放进ref这个盒子里,Vue就能自动追踪它的变化。访问或修改盒子里的值,需要用.value

第三,<script setup> 这是Vue 3推荐的语法糖,它帮你省掉了setup()函数的定义和return语句。在<script setup>里声明的变量和函数,模板可以直接使用。

用一张图来对比两种写法的思维差异:

go 复制代码
Options API 的组织方式(按类型分)     Composition API 的组织方式(按功能分)
┌─────────────────────┐            ┌─────────────────────┐
│ data:               │            │ 🔢 计数器功能:      │
│   count             │            │   count = ref(0)     │
│   searchKey         │            │   increment()        │
│   userInfo          │            │   doubleCount        │
├─────────────────────┤            │   watch(count)       │
│ methods:            │            ├─────────────────────┤
│   increment         │            │ 🔍 搜索功能:        │
│   handleSearch      │            │   searchKey = ref('')│
│   fetchUser         │            │   handleSearch()     │
├─────────────────────┤            │   filteredList       │
│ computed:           │            ├─────────────────────┤
│   doubleCount       │            │ 👤 用户功能:        │
│   filteredList      │            │   userInfo = ref({}) │
│   fullName          │            │   fetchUser()        │
├─────────────────────┤            │   fullName           │
│ watch:              │            └─────────────────────┘
│   count             │
│   searchKey         │
└─────────────────────┘

左边是"按抽屉分类",右边是"按事情分类"。哪个更容易维护,一目了然。

进阶三板斧:computed、watch、生命周期

掌握了ref,咱们再学三个核心工具。

第一板斧:computed------自动计算的"公式单元格"

用过Excel吗?你在A1输入数字,B1写个公式=A1*2,A1一变,B1自动变。computed就是Vue里的"公式单元格"。

go 复制代码
<script setup>
import { ref, computed } from 'vue'

const count = ref(0)

function increment() {
  count.value++
}

// doubleCount 会随 count 自动更新,不需要你手动维护
const doubleCount = computed(() => count.value * 2)
</script>

doubleCount不是一个普通变量,它是一个响应式的计算属性count变了,doubleCount自动变。你不需要写任何"同步逻辑",Vue帮你搞定。

第二板斧:watch------变化的"监控摄像头"

有时候你不只是想"自动算",还想在数据变化时做点什么事 ------比如发请求、记日志、弹提示。这时候就需要watch

go 复制代码
<script setup>
import { ref, watch } from 'vue'

const count = ref(0)

function increment() {
  count.value++
}

watch(count, (newVal, oldVal) => {
  console.log(`计数从 ${oldVal} 变成了 ${newVal}`)

  // 实际场景:比如搜索框输入变化时,自动请求接口
  // 比如分页页码变化时,自动加载下一页数据
})
</script>

watch的回调会告诉你新值和旧值 ,让你能精确地响应变化。在实际项目中,watch最常见的用途包括:

  • 监听搜索关键词变化,做防抖请求

  • 监听路由参数变化,重新加载页面数据

  • 监听表单字段变化,实时校验

第三板斧:onMounted------组件"上岗"后的第一件事

组件挂载到页面上之后,你通常需要做一些初始化工作------请求接口、初始化第三方库、设置定时器。这就是onMounted的用武之地。

go 复制代码
<script setup>
import { ref, onMounted } from 'vue'

const message = ref('加载中...')

onMounted(() => {
  // 模拟接口请求
  setTimeout(() => {
    message.value = '数据加载完成 ✅'
  }, 1000)
})
</script>

<template>
  <p>{{ message }}</p>
</template>

在Options API里,你得把这段逻辑写在mounted()选项里。但在组合式API中,onMounted就是一个普通函数调用,你可以把它和相关的数据、方法写在一起,不再需要"跳来跳去"。

组合式API的"杀手级特性":Composables

前面讲的都是"怎么在一个组件里用"。但组合式API真正的威力,在于跨组件复用逻辑

在Options API时代,复用逻辑主要靠mixins。但用过的人都知道,mixins有三大坑:

go 复制代码
Mixins 的三大坑:
┌──────────────────────────────────────────────┐
│ ❌ 命名冲突:多个mixin可能定义同名属性/方法    │
│ ❌ 来源不明:模板里用的变量,不知道来自哪个mixin │
│ ❌ 隐式依赖:mixin之间可能存在看不见的依赖关系   │
└──────────────────────────────────────────────┘

组合式API的解决方案是Composables(组合式函数)。它本质上就是一个普通的JavaScript函数,返回响应式数据和方法。

来看个实际例子。假设你的项目里有多个组件都需要"计数器"功能:

go 复制代码
// useCounter.js
import { ref } from'vue'

exportfunction useCounter(initialValue = 0) {
const count = ref(initialValue)

function increment() {
    count.value++
  }

function decrement() {
    count.value--
  }

function reset() {
    count.value = initialValue
  }

return { count, increment, decrement, reset }
}

在任何组件里使用:

go 复制代码
<script setup>
import { useCounter } from './useCounter'

// 用法一:默认从0开始
const { count, increment, decrement, reset } = useCounter()

// 用法二:从100开始计数
const { count: score, increment: addScore } = useCounter(100)
</script>

看到了吗?这就是普通的JavaScript函数调用和解构赋值。没有黑魔法,没有隐式注入,每个变量从哪来,一目了然

再来一个更贴近实际开发的例子------封装一个通用的"接口请求"组合函数:

go 复制代码
// useFetch.js
import { ref } from'vue'

export function useFetch(url) {
const data = ref(null)
const loading = ref(true)
const error = ref(null)

  fetch(url)
    .then(res => res.json())
    .then(json => {
      data.value = json
    })
    .catch(err => {
      error.value = err.message
    })
    .finally(() => {
      loading.value = false
    })

return { data, loading, error }
}

在组件中使用:

go 复制代码
<script setup>
import { useFetch } from './useFetch'

const { data, loading, error } = useFetch('https://api.example.com/users')
</script>

<template>
  <div v-if="loading">加载中...</div>
  <div v-else-if="error">出错了:{{ error }}</div>
  <ul v-else>
    <li v-for="user in data" :key="user.id">{{ user.name }}</li>
  </ul>
</template>

三行代码搞定接口请求、加载状态、错误处理。这种复用方式,比mixins不知道高到哪里去了。

一张图看懂:什么时候用Composition API?

go 复制代码
你的场景是什么?
        │
        ▼
┌───────────────┐    是    ┌──────────────────────┐
│ 简单的小组件? ├────────→│ Options API 完全够用   │
│(< 100行代码)│          │ 不用强行切换           │
└───────┬───────┘          └──────────────────────┘
        │ 否
        ▼
┌───────────────┐    是    ┌──────────────────────┐
│ 需要跨组件     ├────────→│ Composables 是最优解   │
│ 复用逻辑?     │          │ 告别 mixins           │
└───────┬───────┘          └──────────────────────┘
        │ 否
        ▼
┌───────────────┐    是    ┌──────────────────────┐
│ 组件逻辑复杂? ├────────→│ Composition API       │
│(多个关注点)  │          │ 按功能分组,更好维护    │
└───────┬───────┘          └──────────────────────┘
        │ 否
        ▼
┌──────────────────────────┐
│ 新项目 / 团队协作?       │
│ → 推荐 Composition API   │
│   统一代码风格,降低协作成本│
└──────────────────────────┘

写在最后:不是"新的"替代"旧的",而是思维的升级

很多同学一看到"新API"就焦虑:是不是Options API要被废弃了?我之前学的是不是白学了?

大可不必。Vue官方明确表示:Options API不会被移除,两种写法会长期共存

但如果你问我的建议------

如果你是Vue新手,直接从Composition API学起。它更接近原生JavaScript,理解成本反而更低。

如果你是Vue老手,新功能用Composition API写,老代码按需迁移。不必一刀切,但掌握这个能力是进阶的必经之路。

如果你是团队Leader,新项目统一Composition API + <script setup>。代码一致性和可维护性的提升,你的组员会感谢你的。

组合式API的本质不是语法层面的更新,而是代码组织思维的升级。它让你从"按类型分类"转向"按功能分类",让代码像搭积木一样灵活组合。

这一步,迟早要迈。不如,就从今天开始。

如果这篇文章对你有帮助,欢迎 点赞 👍 让更多人看到,分享 🔗 给你身边正在学Vue的朋友,也欢迎在评论区聊聊你从Options API切换到Composition API的体验!

关注 「前端达人」,和数万前端开发者一起进阶,每周分享最实用的前端干货 🚀

相关推荐
Dxy12393102162 小时前
Python检查JSON格式错误的多种方法
前端·python·json
chao-Cyril2 小时前
从入门到进阶:前端开发的成长之路与实战感悟
前端·javascript·vue.js
shalou29013 小时前
Spring 核心技术解析【纯干货版】- Ⅶ:Spring 切面编程模块 Spring-Instrument 模块精讲
前端·数据库·spring
大时光3 小时前
js 封装 动画效果
前端
大时光3 小时前
html翻页时钟 效果
前端
大猫子的技术日记3 小时前
2025 AI Agent 开发实战指南:从上下文工程到多智能体协作
前端·人工智能·bootstrap
前端达人3 小时前
被JavaScript忽视的Web Animations API:为什么说它是前端动画的真正未来?
开发语言·前端·javascript·ecmascript
忧郁的橙子.3 小时前
04-从零搭建本地AI对话系统:Ollama + DeepSeek-R1:7B + Streamlit
前端·chrome
PTC4 小时前
做了个 EPUB 阅读器,被「阅读进度同步」折磨了一周,总结 4 个血泪教训
前端