logo
Vue 入门:现代化的渐进式 JavaScript 框架

什么是组合式函数?

组合式函数(Composables)是 Vue 3 中一个非常重要的概念,简单来说,它是一种将复杂的逻辑提取到可重用函数中的方式。这些函数的名字通常以”use”开头,比如 useMousePositionuseUserAuth 等。

从不同编程语言视角理解组合式函数

如果你来自其他编程语言背景,下面的类比可能会帮助你更好地理解组合式函数:

为什么采用这种设计?

不同编程范式都有其处理代码复用的方式:

  • Go 偏向于组合而非继承
  • Java 常用依赖注入和面向接口编程
  • Python 喜欢使用装饰器和上下文管理器
  • React 采用 Hooks 模式
  • 函数式编程倾向于高阶函数和组合
  • PHP 使用 Trait 实现代码复用

Vue 的组合式函数汲取了这些优秀实践的精华:

  • 像 Go 一样偏好组合
  • 像 Java 的依赖注入一样清晰可追踪
  • 像 Python 的上下文管理器一样优雅地处理资源
  • 像 React Hooks 一样灵活
  • 像函数式编程一样支持组合
  • 比 PHP 的 Trait 提供更好的封装性和灵活性

为什么需要组合式函数?

从 Mixins 说起

在讲组合式函数之前,我们需要先了解在 Vue 2 时代人们是如何复用代码的。当时最主要的代码复用方式就是 Mixins(混入)。

什么是 Mixins?

Mixins 是一种代码复用的机制,你可以把它想象成一个”配方”,这个配方包含了一组预定义的功能(数据属性、方法、生命周期钩子等),可以被混入到任何组件中。当一个组件使用 mixin 时,mixin 中的所有功能都会被”混合”进入该组件中。

这就像是在烘焙时,你有一个基础的蛋糕配方(mixin),可以被用在不同的蛋糕(组件)中,每个使用这个配方的蛋糕都会具备配方中定义的基本特性。

让我们看一个具体的例子:

看起来很方便对吧?但是这种方式存在一些严重的问题:

  1. 命名冲突

    • 如果组件自己定义了一个叫 user 的数据属性,它会和 mixin 中的 user 发生冲突
    • 更糟糕的是,当使用多个 mixin 时,它们之间也可能发生命名冲突
    • 你无法轻易地知道哪个 mixin 的属性会覆盖另一个
  2. 数据来源不清晰

    • 在组件中看到 this.user,你不知道这个属性是来自组件本身,还是来自某个 mixin
    • 需要在代码间来回跳转才能找到数据的真正来源
    • 这种”隐式依赖”让代码难以维护
  3. 复用性差

    • mixin 中的所有东西都会被合并到组件中,你不能选择性地只使用其中的一部分
    • 无法向 mixin 传递参数来改变其行为
    • 多个 mixin 的合并规则复杂,有时会产生意想不到的结果

组合式函数:更好的解决方案

Vue 3 引入的组合式函数解决了上述所有问题。让我们看看同样的功能用组合式函数如何实现:

组合式函数的优势

  1. 更清晰的数据来源

    • 使用组合式函数时,我们需要显式地导入和调用它
    • 返回的值可以自由命名,避免冲突
    • 代码追踪变得容易,知道每个值的来源
  2. 更好的类型推导

    • TypeScript 可以更好地推导组合式函数的返回值类型
    • 提供更好的 IDE 支持和代码提示
  3. 更灵活的组合方式

    • 可以像普通函数一样接收参数
    • 可以根据条件决定是否使用某个组合式函数
    • 可以在一个组合式函数中使用其他组合式函数

实际案例:创建一个鼠标跟踪器

让我们通过一个简单的例子来说明组合式函数的强大之处:

useMousePosition.js
import { ref, onMounted, onUnmounted } from 'vue'
export function useMousePosition() {
const x = ref(0)
const y = ref(0)
function update(event) {
x.value = event.pageX
y.value = event.pageY
}
onMounted(() => {
window.addEventListener('mousemove', update)
})
onUnmounted(() => {
window.removeEventListener('mousemove', update)
})
return { x, y }
}

在组件中使用:

<template>
<div>
鼠标位置:({{ x }}, {{ y }})
</div>
</template>
<script setup>
import { useMousePosition } from './useMousePosition'
const { x, y } = useMousePosition()
</script>

最佳实践

  1. 命名规范

    • 组合式函数应该始终以”use”开头
    • 返回一个包含相关状态和方法的对象
    • 名称应该能清晰地表达其功能
  2. 保持功能单一

    • 每个组合式函数应该只关注一个功能点
    • 可以通过组合多个小的组合式函数来实现复杂功能
  3. 响应式数据处理

    • 使用 refreactive 来确保返回的数据是响应式的
    • 考虑是否需要使用 computed 来派生状态
  4. 生命周期处理

    • 在必要时使用 onMountedonUnmounted 等生命周期钩子
    • 确保正确清理副作用(如事件监听器、定时器等)

常见使用场景

  1. 状态管理

    • 用户认证状态
    • 主题切换
    • 多语言支持
  2. 功能封装

    • 表单验证
    • API 请求处理
    • 页面滚动行为
  3. 浏览器 API 封装

    • localStorage 操作
    • 地理位置获取
    • 设备方向检测

结语

组合式函数是 Vue 3 中最强大的特性之一,它不仅解决了过去 mixins 带来的问题,还提供了更优雅、更灵活的代码复用方式。通过合理使用组合式函数,我们可以:

  • 提高代码的可维护性
  • 增强代码的可读性
  • 实现更好的类型推导
  • 使逻辑复用变得更加简单

当你开始一个新的 Vue 3 项目时,应该优先考虑使用组合式函数来组织和复用代码逻辑。它不仅能让你的代码更加清晰,还能大大提高开发效率。