Vue 3 组合式 API 详解:告别 Mixins,拥抱函数式编程

🆚 主要区别

特性 Vue 2(选项式 API) Vue 3(组合式 API)
逻辑组织方式 按选项分类(如data、methods、computed 等) 按功能逻辑分组(通过 setup()<script setup>
代码复用 依赖 Mixins 或高阶组件(容易导致命名冲突和逻辑分散) 使用 Composable 函数(更清晰、可复用性强)
响应式系统 基于 Object.defineProperty 实现 基于 Proxy 实现,性能更好、功能更强
TypeScript 支持 支持有限,类型推导不够完善 原生支持 TypeScript,类型推导更友好
编程范式 命令式为主 声明式 + 函数式

一、Vue 2 的痛点:Mixins 的"甜蜜陷阱"

在 Vue 2 中,当我们需要复用一段逻辑时,最常见的做法是使用 Mixins(混入) 。它的使用非常简单:只需要把公共逻辑抽离成一个对象,然后通过 mixins 属性注入到组件中即可。

javascript 复制代码
const myMixin = {
  data() {
    return { message: 'Hello' }
  },
  methods: {
    greet() {
      console.log(this.message)
    }
  }
}

export default {
  mixins: [myMixin],
  mounted() {
    this.greet() // 输出 "Hello"
  }
}

看似方便,但 Mixins 却埋下了不少隐患:

  1. 命名冲突:如果两个 Mixins 定义了同名属性或方法,后一个会默默覆盖前一个,导致难以排查的 bug。
  2. 逻辑碎片化:随着组件变复杂,逻辑会被分散到多个 Mixins 中,最终让人摸不清头绪。
  3. 调试困难:组件中的数据来源模糊不清,增加了维护成本。

这些问题让 Mixins 成为了"甜蜜的负担"。


二、Vue 3 的革新:Composable 函数登场

Vue 3 彻底改变了逻辑复用的方式,推出了 Composable 函数 。这是一种基于函数式编程思想的设计,核心理念是"把逻辑封装成独立的函数,按需调用"。

来看一个经典的例子------计数器:

typescript 复制代码
import { ref } from 'vue'

function useCounter(initialValue = 0) {
  const count = ref(initialValue)
  const increment = () => count.value++
  const decrement = () => count.value--

  return { count, increment, decrement }
}

export default {
  setup() {
    const { count, increment, decrement } = useCounter(10)
    return { count, increment, decrement }
  }
}

这段代码的优点显而易见:

  • 所有关于计数器的逻辑都集中在 useCounter 函数中,结构清晰;
  • 调用时只需解构返回值,无需担心命名冲突;
  • 可以轻松复用到其他组件中,真正做到"一次编写,多处使用"。

Composable 函数的本质其实就是纯函数:输入确定则输出确定,没有副作用,逻辑高度解耦。


三、响应式系统的蜕变:从 defineProperty 到 Proxy

除了逻辑复用,Vue 3 还对底层的响应式系统进行了彻底重构。

Vue 2 的响应式原理

Vue 2 使用 Object.defineProperty 来劫持对象属性的变化:

javascript 复制代码
const obj = {}
Object.defineProperty(obj, 'name', {
  get() {
    console.log('读取 name')
    return this._name
  },
  set(value) {
    console.log('设置 name:', value)
    this._name = value
  }
})

这种方式虽然实现了基本的响应式功能,但也存在明显缺陷:

  1. 无法监听新增属性 :必须通过 $set 手动触发更新;
  2. 数组索引赋值失效 :如 arr[0] = newValue 不会被监听;
  3. 性能开销大:需要递归遍历所有属性。

Vue 3 的响应式原理

Vue 3 换用了 ES6 的 Proxy,它可以拦截整个对象的所有操作:

javascript 复制代码
const target = { name: 'Vue' }
const proxy = new Proxy(target, {
  get(target, key) {
    console.log(`读取 ${key}`)
    return target[key]
  },
  set(target, key, value) {
    console.log(`设置 ${key}: ${value}`)
    target[key] = value
    return true
  }
})

Proxy 的优势在于:

  • 自动支持新增属性和删除属性;
  • 数组操作也能完美监听;
  • 性能更好,采用惰性初始化策略。

这种改进不仅提升了开发体验,也让 Vue 3 的响应式系统更加健壮。


四、背后的思想:函数式编程的魅力

Vue 3 的设计深受 函数式编程 的影响。那什么是函数式编程呢?简单来说,它是一种以函数为核心的编程范式,强调以下几个核心理念:

1. 纯函数(Pure Function)

函数的行为只依赖输入参数,不修改外部状态。例如:

javascript 复制代码
function add(a, b) {
  return a + b
}
add(1, 2) // 始终返回 3

2. 不可变性(Immutability)

数据一旦创建就不能被修改,只能通过创建副本来反映变化:

javascript 复制代码
const arr = [1, 2, 3]
const newArr = [...arr, 4] // 创建新数组而不是修改原数组

3. 声明式编程(Declarative Programming)

关注"做什么"而不是"怎么做"。比如:

javascript 复制代码
// 命令式写法
for (let i = 0; i < arr.length; i++) {
  console.log(arr[i])
}

// 声明式写法
arr.forEach(item => console.log(item))

Vue 3 如何体现函数式思想?

  • Composable 函数是典型的纯函数,它们接受参数、返回结果,不对外部造成影响;
  • Proxy 响应式系统通过代理层隔离副作用,让原始数据始终保持纯净;
  • 模板语法鼓励开发者使用声明式的方式描述 UI,而不是手动操作 DOM。

在 Vue 2 的项目中,一个用户管理页面的 datamethodscomputed 分散在各处,维护困难。使用 Composition API 重构时,可以将代码按照逻辑功能分组,代码更清晰、可复用性更强。例如:我将所有与'用户表单验证'相关的逻辑(响应式数据、验证函数、规则)抽取为 useUserForm Hook。这使得相同逻辑在不同组件间复用变得清晰 ,代码更像是编写纯函数。在大型项目中,我们通常会按 '功能域'(如useTableuseAuth 来组织组合式函数,并与业务组件分离,形成清晰的基础设施层。


如果你喜欢这篇文章,欢迎点赞、收藏或分享给更多朋友。也欢迎在评论区留下你的看法和经验,我们一起交流成长!

相关推荐
漂流瓶jz6 小时前
BEM、OOCSS、SMACSS、ITCSS、AMCSS、SUITCSS:CSS命名规范简介
前端·css·代码规范
陈随易10 小时前
真的,你可以不用TypeScript
前端·后端·程序员
郑州光合科技余经理11 小时前
代码展示:PHP搭建海外版外卖系统源码解析
java·开发语言·前端·后端·系统架构·uni-app·php
唐璜Taro11 小时前
Vue3 + TypeScript 后台管理系统完整方案
前端·javascript·typescript
dustcell.11 小时前
haproxy七层代理
java·开发语言·前端
掘金酱12 小时前
「寻找年味」 沸点活动|获奖名单公示🎊
前端·人工智能·后端
颜酱12 小时前
栈的经典应用:从基础到进阶,解决LeetCode高频栈类问题
javascript·后端·算法
患得患失94912 小时前
【前端】前端动画优化的核心
前端
Xin_z_12 小时前
Vue3 + Sticky 锚点跳转被遮挡问题解决方案
前端·javascript·vue.js
REDcker12 小时前
WebCodecs VideoDecoder 的 hardwareAcceleration 使用
前端·音视频·实时音视频·直播·webcodecs·videodecoder