在 Vue 3 中,虽然依然支持 Options API 风格的 Mixins,但更推荐使用 Composition API 来实现代码复用,因为它能更好地解决传统 Mixins 在可读性、命名冲突和类型推断方面的一些痛点。

下面的表格能帮你快速了解这两种方式的主要区别:

特性维度 Mixins (Options API 风格) Composition API (组合式函数)
代码复用方式 通过选项(data, methods 等)合并 通过函数调用和返回值
可读性 逻辑分散 across 多个选项,来源不清晰 逻辑集中,按功能组织
命名冲突 容易发生,需小心处理合并策略 通过解构重命名,冲突风险低
类型支持 较弱 对 TypeScript 支持良好
灵活性 相对固定 高,可以像普通函数一样组合和嵌套

🍰 传统 Mixins 的写法

这种方式是将组件的公共逻辑通过选项的形式定义在一个对象中。

  1. 定义 Mixin
    创建一个独立的文件(例如 useCounterMixin.js),使用 Options API 的风格定义数据和方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // useCounterMixin.js
    export const useCounterMixin = {
    data() {
    return {
    mixinCount: 0
    }
    },
    methods: {
    mixinIncrement() {
    this.mixinCount++;
    }
    },
    mounted() {
    console.log('Mixin mounted!');
    }
    }
  2. 在组件中使用
    在组件中通过 mixins 选项引入,Vue 会自动合并这些选项。当组件和 Mixin 有同名属性或方法时,默认情况下,组件的选项会覆盖 Mixin 的。对于生命周期钩子两者都会被执行,且 Mixin 的钩子先于组件自身的钩子执行

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    <template>
    <div>
    <p>Count from mixin: {{ mixinCount }}</p>
    <button @click="mixinIncrement">Increment from Mixin</button>
    </div>
    </template>

    <script>
    import { useCounterMixin } from './useCounterMixin'

    export default {
    mixins: [useCounterMixin],
    // 组件自己的 data、methods 等选项...
    mounted() {
    console.log('Component mounted!');
    // 输出顺序:
    // "Mixin mounted!"
    // "Component mounted!"
    }
    }
    </script>

💡 使用 Composition API 实现逻辑复用

Composition API 通过“组合式函数”来实现复用,这是一个更符合 JavaScript 原生思维的方式。

  1. 创建组合式函数
    创建一个函数(通常以 use 开头),在函数内部使用 ref, reactive, computed 等 Composition API 定义响应式数据和逻辑,并返回需要暴露给组件的值。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    // useCounter.js
    import { ref, computed, onMounted } from 'vue'

    export function useCounter(initialValue = 0) {
    // 响应式状态
    const count = ref(initialValue)

    // 计算属性
    const double = computed(() => count.value * 2)

    // 方法
    function increment() {
    count.value++
    }

    // 生命周期钩子
    onMounted(() => {
    console.log('Counter composition mounted!')
    })

    // 返回所有需要使用的数据和方法
    return {
    count,
    double,
    increment
    }
    }
  2. 在组件中使用组合式函数
    在组件的 setup() 函数或 <script setup> 语法糖中,调用组合式函数并获取其返回的值。你可以按需重命名,有效避免了命名冲突。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <!-- 使用 <script setup> 语法 -->
    <template>
    <div>
    <p>Count: {{ count }}</p>
    <p>Double: {{ double }}</p>
    <button @click="increment">Increment</button>
    </div>
    </template>

    <script setup>
    // 导入组合式函数
    import { useCounter } from './useCounter'

    // 调用函数,解构返回值
    const { count, double, increment } = useCounter(10) // 可以传递初始参数
    </script>

✅ 如何选择与最佳实践

  • 选择建议

    • 对于新项目或复杂的逻辑复用,强烈推荐使用 Composition API。它带来了更好的可维护性和类型支持。
    • 如果你是在维护一个旧的、主要使用 Options API 的 Vue 2 项目,或者复用的逻辑非常简单,可以继续使用 Mixins。
  • 最佳实践

    • 单一职责:无论是 Mixin 还是组合式函数,都尽量让其只负责一个明确的功能。
    • 清晰命名:在 Mixin 中,可以考虑使用特定的前缀来减少命名冲突的风险(例如 mixinCount)。在组合式函数中,则可以利用解构重命名。
    • 明确依赖:在组合式函数中,对于需要从外部接收的参数,使用 refreactive 保持其响应性。

总而言之,Composition API 通过原生 JavaScript 的函数机制进行逻辑组合和复用,提供了比 Mixins 更灵活和可控的方式,是现代 Vue 应用代码复用的首选。

希望这份讲解能帮助你顺利地在 Vue 3 中实现代码复用。如果你在具体的实现过程中遇到问题,可以随时提问。