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 来组织组合式函数,并与业务组件分离,形成清晰的基础设施层。


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

相关推荐
weixin_3823952313 分钟前
为小工厂量身打造:本地部署的物料管理系统带缺料计算
前端·制造
__zRainy__19 分钟前
解决pnpm v10+不自动构建
前端·pnpm·工程化
猫猫不是喵喵.1 小时前
Vue3 Props 属性
前端·javascript·vue.js
醉城夜风~2 小时前
CSS元素显示模式(display)
前端·css
AI大模型-小华3 小时前
Codex 三方充值快速入门指南
java·前端·数据库·chatgpt·ai编程·codex·chatgpt pro
做前端的娜娜子5 小时前
同一链接实现 PC Web 与移动 H5 自适应
前端·掘金·金石计划
小帅不太帅5 小时前
架构没变、规模没变,DeepSeek V4 Flash 正式版凭什么暴涨 47 分?
前端·aigc·deepseek
jarvisuni5 小时前
DeepSeekFlash前端依旧拉垮,而且变慢了很多!
前端·javascript·算法
卷福同学7 小时前
AI编程出海第二步:验证关键词能否做站
前端·人工智能·后端