Vue Mixin技术详解(附带实例)
使用组件开发的一大优势在于可以提高代码的复用性。通过 Mixin 技术,组件的复用性可以得到进一步的提高。
首先,新建一个名为 demo.mixin.html 的测试文件,编写 3 个简单的示例组件,核心代码如下:

图 1 组件示意图
在上述代码中定义的 3 个示例组件中,每个组件都定义了一个名为 title 的外部属性,这部分代码其实可以抽离出来作为独立的“功能模块”,需要此功能的组件只需要“混入”此功能模块即可。示例代码如下:
a、b、c 和 d 四个属性。
如果属性的定义有冲突,则会以组件内部定义的为准,例如:
生命周期函数的这类配置项的混入与属性类的配置项的混入略有不同,不重名的生命周期函数会被完整混入组件,重名的生命周期函数被混入组件时,在函数触发时,会先触发 Mixin 对象中的实现,再触发组件内部的实现。这类似于面向对象编程中子类对父类方法的覆写。例如:
另外,在示例代码中,很多地方我们采用了选项式的 API 来编写组件,其实 Mixin 技术在 Vue3 之后已经不再被推荐使用了,Vue3 之所以依然支持 Mixin 的语法,主要是为了兼容旧代码。
在 Vue3 中,如果我们需要实现逻辑的复用,可以将其封装为函数,在组合式 API 中导入函数直接进行使用。
使用Mixin来定义组件
当我们开发大型前端项目时,可能会定义非常多的组件,这些组件中可能有部分功能是通用的,对于这部分通用的功能,如果每个组件都编写一遍将会非常烦琐,而且不利于之后的维护。首先,新建一个名为 demo.mixin.html 的测试文件,编写 3 个简单的示例组件,核心代码如下:
<div id="Application"> <my-com1 title="组件 1"></my-com1> <my-com2 title="组件 2"></my-com2> <my-com3 title="组件 3"></my-com3> </div> <script> const App = Vue.createApp({}); const com1 = { props: ['title'], // 外部属性 title template: ` <div style="border: red solid 2px;"> {{ title }} </div> ` }; const com2 = { props: ['title'], // 外部属性 title template: ` <div style="border: blue solid 2px;"> {{ title }} </div> ` }; const com3 = { props: ['title'], // 外部属性 title template: ` <div style="border: green solid 2px;"> {{ title }} </div> ` }; App.component("my-com1", com1); App.component("my-com2", com2); App.component("my-com3", com3); App.mount("#Application"); </script>运行上述代码,效果如下图所示:

图 1 组件示意图
在上述代码中定义的 3 个示例组件中,每个组件都定义了一个名为 title 的外部属性,这部分代码其实可以抽离出来作为独立的“功能模块”,需要此功能的组件只需要“混入”此功能模块即可。示例代码如下:
const App = Vue.createApp({}); // 将组件通用的部分定义成 mixin 模块 const myMixin = { props: ['title'] }; const com1 = { mixins: [myMixin], // 引入需要的 mixin 模块 template: ` <div style="border: red solid 2px;"> {{ title }} </div> ` }; const com2 = { mixins: [myMixin], // 引入需要的 mixin 模块 template: ` <div style="border: blue solid 2px;"> {{ title }} </div> ` }; const com3 = { mixins: [myMixin], // 引入需要的 mixin 模块 template: ` <div style="border: green solid 2px;"> {{ title }} </div> ` };如以上代码所示,我们可以定义一个混入对象,混入对象中可以包含任意的组件定义选项,当此对象被混入组件时,组件会将混入对象中提供的选项引入当前组件内部。这类似于编程语言中的“继承”语法。
Mixin选项的合并
当混入对象与组件中定义了相同的选项时,Vue 可以非常智能地对这些选项进行合并。不冲突的配置将完整合并,冲突的配置会以组件中自己的配置为准,例如:const myMixin = { data() { // 定义 mixin 模块中的数据 return { a: "a", b: "b", c: "c" }; } }; const com = { mixins: [myMixin], setup() { const d = "d"; return { d }; }, // 组件被创建后会调用,用来测试混入的数据情况 created() { // a, b, c, d 都存在 console.log(this.a, this.b, this.c, this.d); } };在上述代码中,混入对象中定义了组件的属性数据,包含 a、b 和 c 三个属性,组件本身定义了 d 属性,最终组件在使用时,其内部的属性包含
a、b、c 和 d 四个属性。
如果属性的定义有冲突,则会以组件内部定义的为准,例如:
const myMixin = { props: ["title"], data() { // 定义 mixin 模块中的数据 return { a: "a", b: "b", c: "c" }; } }; const com = { mixins: [myMixin], setup() { return { c: "C" // 此数据与 mixin 模块中的有冲突,组件内的优先级更高 }; }, // 组件被创建后会调用,用来测试混入的数据情况 created() { // 属性 c 的值为 "C" console.log(this.c); } };
生命周期函数的这类配置项的混入与属性类的配置项的混入略有不同,不重名的生命周期函数会被完整混入组件,重名的生命周期函数被混入组件时,在函数触发时,会先触发 Mixin 对象中的实现,再触发组件内部的实现。这类似于面向对象编程中子类对父类方法的覆写。例如:
// 定义 mixin 对象 const myMixin = { mounted() { console.log("Mixin 对象 mounted"); } }; // 定义组件 const com = { mixins: [myMixin], mounted() { console.log("组件本身 mounted"); } };运行上述代码,当 com 组件被挂载时,控制台会先打印“Mixin对象mounted”之后,再打印“组件本身mounted”。
进行全局Mixin
Vue 也支持对应用进行全局 Mixin 混入。直接对应用实例进行 Mixin 设置即可,示例代码如下:const App = Vue.createApp({}); App.mixin({ mounted() { console.log("Mixin 对象 mounted"); } });需要注意,虽然全局 Mixin 使用起来非常方便,但是这会使其后所有注册的组件都默认被混入这些选项,当程序出现问题时,这会增加排查问题的难度。全局 Mixin 技术非常适合开发插件,如开发组件挂载的记录工具等。
另外,在示例代码中,很多地方我们采用了选项式的 API 来编写组件,其实 Mixin 技术在 Vue3 之后已经不再被推荐使用了,Vue3 之所以依然支持 Mixin 的语法,主要是为了兼容旧代码。
在 Vue3 中,如果我们需要实现逻辑的复用,可以将其封装为函数,在组合式 API 中导入函数直接进行使用。