当多个组件拥有重复的 data
、生命周期钩子或业务函数时,复制粘贴会迅速演变成维护灾难。Vue 生态提供了三条主流路径:Mixin、高阶组件、Composition API。本文按时间线梳理它们的适用场景、合并策略与陷阱,帮助你在 Vue2 与 Vue3 中做出最优技术选型。
一、Mixin:Options API 时代的瑞士军刀
1.基本形态
js
// userMixin.js
export default {
data() {
return { loading: false, error: null }
},
methods: {
async fetchUser(id) {
this.loading = true
// 省略请求逻辑
}
},
created() {
this.fetchUser(this.$route.params.id)
}
}
js
// 组件内部
export default {
mixins: [userMixin],
// 组件独有逻辑
}
2.合并规则(源码视角)
- data:递归合并,冲突时组件优先。
- 生命周期:拼接成数组,按 mixin → 组件 顺序执行。
- methods / components / directives:对象浅合并,键冲突时组件覆盖 mixin。
3.典型问题
- 命名污染:同名变量或方法被静默覆盖,调试困难。
- 来源不透明:
this.xxx
可能来自mixinA
或mixinB
,IDE 无法跳转。 - 多重继承:超过 3 个 mixin 时,执行顺序与数据流向呈指数级复杂度。
Vue 官方建议:单个组件 mixin 数量 ≤ 2,复杂逻辑优先考虑高阶组件或 Composition API。
二、高阶组件(HOC):渲染逻辑的包装模式
通过「组件包裹组件」实现逻辑复用,典型代表是 Vue-Router 的 <router-view>
或 Vuex 的 map*
辅助函数。
js
function withLoading(WrappedComponent) {
return {
data() {
return { loading: false }
},
template: `
<div>
<spinner v-if="loading"/>
<wrapped-component v-bind="$attrs" v-on="$listeners"/>
</div>
`
}
}
优点:数据来源清晰、组合灵活;
缺点:组件嵌套层级加深、props 透传冗长。
三、Composition API:面向未来的逻辑组合
Vue 3 引入 setup
后,逻辑单元被提炼为 Composable 函数:
ts
// useUser.ts
export function useUser(id: Ref<string>) {
const loading = ref(false)
const user = ref(null)
watch(id, async (newId) => {
loading.value = true
user.value = await api.getUser(newId)
loading.value = false
}, { immediate: true })
return { loading, user }
}
ts
// 组件内部
const { loading, user } = useUser(route.params.id as Ref<string>)
- 无命名冲突:变量作用域限于调用方。
- 类型安全:TypeScript 泛型与推导一步到位。
- 树摇友好:未使用的逻辑在构建阶段自动剔除。