Vue 2 的混入(Mixin)是一种在 Vue 组件中分发可复用功能的方式。通过混入,你可以将一些通用的组件选项(如数据、方法、计算属性、生命周期钩子等)提取到一个混入对象中,并在多个组件中重用这些选项,从而实现代码复用和组织。
混入的基础用法
在 Vue 2 中,你可以使用 Vue.mixin()
方法全局注册一个混入对象,这样该混入对象中的选项将被添加到所有 Vue 实例和组件中。另外,你也可以在组件定义时使用 mixins
选项来局部注册一个或多个混入对象。
上例子
代码结构关系如下:
index.vue
javascript
<template>
<div>
<School />
<hr>
<Student />
</div>
</template>
<script>
import Student from './student.vue'
import School from './school.vue'
export default {
components: {
Student,
School
},
data () {
return {}
},
}
</script>
<style scoped>
</style>
school.vue
javascript
<template>
<div>
<h2 @click="showName">学校名称:{{ name }}</h2>
<h2>学校地址:{{ address }}</h2>
</div>
</template>
<script>
//引入混入
import maxin from '../../mixin.js'
import {mixin2} from '../../mixin.js'
export default {
name: 'School',
data() {
return {
name: '高级中学',
address: '阳平镇',
x:10
};
},
//生命周期冲突时,同时使用,而且混入的优先级高于组件本身
mounted() {
console.log(this.x);
},
mixins: [maxin,mixin2],
}
</script>
<style scoped>
</style>
student.vue
javascript
<template>
<div>
<h2 @click="showName">学生姓名:{{ name }}</h2>
<h2>学生性别:{{ sex }}</h2>
</div>
</template>
<script>
import maxin from '../../mixin.js'
export default {
name: 'Student',
data() {
return {
name: '张三',
sex: '男',
age: 18
};
},
mixins: [maxin],
}
</script>
<style scoped>
</style>
上面就是一个父组件和两个子组件的关系,在index.vue中使用了school和student组件。
对于混入呢,其实就是两个重点
①分发 Vue 组件的可复用功能
②解决冲突
(1)分发 Vue 组件的可复用功能
将上面两个子组件的点击事件移入到混入中
建立mixin.js文件
javascript
const maxin= {
methods: {
showName() {
alert(this.name);
}
},
mounted() {
console.log('你好,世界');
}
}
export const mixin2={
data(){
return{
name:'mixin2',
x:100,
y:800
}
}
}
export default maxin;
这样界面中的点击效果依然可以正常使用
当时做到这里我就发现了,提取公共的可复用功能,这不是就是vue3的自定义hooks吗?事实证明,vue3中使用了组合式API和自定义hooks,就不再使用mixin了。
Vue 3 引入了 Composition API,这是一种新的、可选的 API,用于组织和重用 Vue 组件的逻辑。Composition API 的主要优势在于其提供了比混入 (mixin) 更直观、更灵活的方式来组织和共享代码。以下是为什么 Vue 3 使用 Composition API 后,可能不再需要混入的一些原因:
-
更好的逻辑复用:混入允许你在多个组件之间共享代码,但当混入变得复杂时,很难跟踪哪些组件使用了哪些混入的逻辑。Composition API 通过自定义的 hooks(函数)来复用逻辑,这些 hooks 可以明确地在需要的组件中导入和使用,从而提供了更清晰的复用机制。
-
更直观的状态管理 :在混入中,来自不同混入的对象属性可能会发生冲突,尤其是当它们有相同的名称时。Composition API 通过使用
ref
、reactive
和computed
等函数来创建响应式状态,这些状态是局部的,并且只在setup
函数内部或其返回的模板中使用,从而避免了名称冲突的问题。 -
更灵活的代码组织 :混入通常会将不同的逻辑片段(如生命周期钩子、方法等)分散到多个混入对象中。这可能会导致代码难以理解和维护。Composition API 允许你将相关的逻辑组织在同一个
setup
函数或自定义 hook 中,使代码更加集中和模块化。 -
更好的类型支持:TypeScript 用户在使用混入时可能会遇到类型推断的问题,因为混入的属性和方法可能会与组件自己的属性和方法混合在一起。而 Composition API 与 TypeScript 结合得更好,因为它允许你明确地定义和返回响应式状态和函数,从而更容易进行类型检查和推断。
-
更少的魔法:混入的工作方式有时会被视为"魔法",因为它会在组件背后默默地添加属性和方法。这可能会导致调试困难或不可预测的行为。相比之下,Composition API 更加显式,你明确地知道哪些逻辑被添加到了组件中。
(2)解决冲突
那可能就会有一个疑问,如果混入中的data中的数据和组件自身的数据冲突了怎么办?
答案就是,这种情况下,以组件自身的为主。
我们可以看到,以组件自身的数据为主
还有一种特殊一点的情况,就是生命周期,如果组件和混入都使用了相同的生命周期,那么两种声明周期种的代码将都会保留,并且执行顺序是先混入,后组件自身。
混入的合并策略
当组件和混入对象包含相同的选项时,Vue 会使用特定的合并策略来处理这些冲突。以下是一些常见的合并策略:
-
数据对象(data):组件自身的数据对象和混入对象的数据对象是合并的,以组件自身的数据优先。如果键名冲突,组件自身的数据将覆盖混入对象中的数据。
-
生命周期钩子(如 created、mounted 等):混入对象的钩子函数将在组件自身的钩子函数之前调用。这些钩子函数不会合并成一个数组,而是会依次执行。这意味着你可以利用混入来在组件的生命周期钩子之前或之后执行一些额外的逻辑。
-
方法(methods) 、计算属性(computed) 和 侦听器(watchers):如果组件和混入对象定义了相同名称的方法、计算属性或侦听器,组件自身的定义将优先,并且会覆盖混入对象中的定义。
混入的注意事项
虽然混入提供了一种灵活的方式来复用代码,但在使用时也需要注意以下几点:
-
命名冲突:由于混入对象的选项会与组件的选项合并,因此需要小心处理命名冲突的情况。为了避免潜在的冲突,最好使用具有明确含义和独特性的命名。
-
依赖关系:混入对象之间可能存在依赖关系,这可能导致复杂的依赖链和难以预测的行为。因此,在使用多个混入对象时,需要确保它们之间的依赖关系是清晰和可控的。
-
代码可读性:过度使用混入可能会导致代码变得难以阅读和理解。因此,在使用混入时,需要权衡代码的复用性和可读性,并尽量保持代码的简洁和清晰。
最后就是混入的使用
引入混入(Mixin)的方式主要有两种,分别是单页面引入和全局混入。
-
单页面引入:
- 首先,创建一个包含混入对象的文件。通常,这个文件会定义一个混入对象,该对象可以包含数据、方法、生命周期钩子等组件选项。
- 然后,在需要使用混入的组件中,通过
import
语句引入这个混入对象。 - 最后,在组件的配置对象中,使用
mixins
选项注册这个混入对象。这样,混入对象中的选项就会被合并到组件的选项中。
上面介绍的方式就是单页面引入。
-
全局混入:
- 全局混入的方式与单页面引入类似,首先需要创建一个混入对象。
- 不同的是,全局混入是在应用的入口文件(如
main.js
)中进行引入和注册的。 - 使用
Vue.mixin(mixin)
方法来注册全局混入对象。这将影响到之后创建的每一个Vue实例,包括第三方组件。 - 需要注意的是,全局混入应谨慎使用,因为它可能会影响应用的性能和可维护性。
如果是全局引入,则需要再main.ts中进行引入【项目中的方式】,而不需要在页面中进行引入了,页面中直接使用。
javascript
//全局混入
import {mixin2} from './mixin'
Vue.mixin(mixin2)
这两种方式各有优缺点,单页面引入更加灵活,可以根据需要选择性地引入混入;而全局混入则可以在整个应用中统一添加某些功能或行为,但也可能带来一些不必要的副作用。因此,在使用混入时,应根据具体需求和使用场景来选择合适的方式。