Vue — 详解mixins混入使用,应用场景
混入是vue官方文档提出的 关于vue复用性的一种方式,看了文档似懂,查找了下网上的讲解,整理下好好缕一缕这个东西
前言
当我们的项目越来越大,我们会发现组件之间可能存在很多相似的功能,你在一遍又一遍的复制粘贴相同的代码段(data,method,watch、mounted等),如果我们在每个组件中去重复定义这些属性和方法会使得项目出现代码冗余并提高了维护难度,针对这种情况官方提供了Mixins特性
一、什么是Mixins? mixins是一个js对象
混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。
mixins(混入),官方的描述是一种分发 Vue 组件中可复用功能的非常灵活的方式,mixins是一个js对象,它可以包含我们组件中script项中的任意功能选项,如data、components、methods 、created、computed等等。
我们只要将共用的功能以对象的方式传入 mixins选项中,当组件引用 mixins对象时所有mixins对象的选项都将被混入该组件本身的选项中来,这样就可以提高代码的重用性,使你的代码保持干净和易于维护。
image.png放大看这张图:右边就是一个混入对象; 左边引用了混入对象
二、什么时候使用Mixins?
当我们存在多个组件中的数据或者功能很相近时,我们就可以利用mixins将公共部分提取出来,通过 mixins封装的函数,组件调用他们是不会改变函数作用域外部的。
作用: 减少data、methods、钩子的重复
🤭🤭🤭🤭
文章最后会举例应用场景~
三、如何创建Mixins?
在src目录下创建一个mixins文件夹,文件夹下新建一个myMixins.js文件。前面我们说了mixins是一个js对象,所以应该以对象的形式来定义myMixins,在对象中我们可以和vue组件一样来定义我们的data、components、methods 、created、computed等属性,并通过export导出该对象
image.png
四、如何使用Mixins?
前面在myMixins.js中输出一个混入对象,然后在需要调用的组件中引入myMixins.js文件即可
image.png
五、Mixins的特点
特点1:方法和参数在各组件中不共享,虽然组件调用了mixins并将其属性合并到自身组件中来了,但是其属性只会被当前组件所识别并不会被共享。
🤭也就是当前组件对mixins的属性的修改,其他也引用了这个mixins的组件并不会受影响。🤭
① 首先我们在混合对象myMixins.js中定义一个age字段和getAge方法
export const myMixins = {
components:{},
data() {
return {
age: 18,
}
},
mounted() {
this.getAge()
},
methods: {
getAge() {
console.log(this.age)
}
}
}
② 此时组件1引用了这个mixins,组件1中对num进行+1操作
// 这是组件1
import { myMixins } from "@/mixins/myMixins.js";
export default {
mixins: [myMixins],
data() {
return {}
},
created() {
this.age++ // 组件1的age变成了19啦
},
}
③ 组件2不进行操作
export default {
mixins: [myMixins],
data() {
return {}
},
}
④ 我们分别切换到两个页面,查看控制台输出。会发现组件1改变了age里面的值,组件2中age值还是混合对象的初始值,并没有随着组件1的增加而改变
image.png
特点2:引入mixins后,组件会对其进行合并,将mixins中的数据和方法拓展到当前组件中来,如果当前组件也有同名称的属性或者方法,在合并的过程中会出现冲突,接下来我们详细了解Mixins合并冲突
六、Mixins合并冲突
【6.1】混入对象里的(components、methods 、computed、data)这些选项,混入组件时选项会被合并,重名冲突时优先采用组件的 🤭,组件中的键会覆盖混入对象的
① 我们在混入对象增加age属性、getAge1方法和getAge2方法
// myMixins.js
export const myMixins = {
components:{},
data() {
return {
age: 18,
}
},
methods: {
getAge1() {
console.log("age1 from mixins =", this.age )
},
getAge2() {
console.log("age2 from mixins =", this.age )
},
}
}
② 我们在引入了myMixins文件的组件中,增加age属性、getAge1方法和getAge3方法
// template.vue
import { myMixins } from "@/mixins/myMixins.js";
export default {
mixins: [myMixins],
data() {
return {
age: 20,
}
},
mounted() {
this.getAge1();
this.getAge2();
this.getAge3();
},
methods: {
getAge1() {
console.log('age1 from template =', this.age)
},
getAge3() {
console.log('age3 from template =', this.age)
},
}
}
③ 我们会发现:
组件中的age覆盖了混合对象的age,
组件的getAge1方法覆盖了混合对象的getAge1方法
image.png
【6.2】值为函数(created、mounted)的选项,混入组件时选项会被合并调用,
🤭 混合对象里的钩子函数在组件里的钩子函数之前调用
// myMixins.js
export const myMixins = {
components:{},
data() {
return {}
},
created() {
console.log('xxx from mixins')
}
}
再看看引用了mixins的组件
import { myMixins } from "@/mixins/myMixins.js";
export default {
mixins: [myMixins],
data() {
return {}
},
created() {
console.log('xxx from template')
}
}
结果 mixins自己的created 比 引用了mixins的组件里的created先执行
image.png
七、全局混入
严重警告:一旦使用全局混入,它将影响每一个之后创建的 Vue 实例。
使用恰当时,这可以用来为自定义选项注入处理逻辑。
// 为自定义的选项 'myOption' 注入一个处理器。
Vue.mixin({
created: function () {
var myOption = this.$options.myOption
if (myOption) {
console.log(myOption)
}
}
})
new Vue({
myOption: 'hello!'
})
// => "hello!"
不建议使用全局混入,全局注册之后会对所有组件都生效,影响比较大,项目大的情况下,建议使用局部注册
八、同时引入多个mixin对象
同时引入多个 mixins: [mixinsTest2,mixinsTest]
在使用局部注册的时候,可同时引入多个混入对象,执行顺序和引入顺序一致,此处便不再赘述了。
结论:
引入多个以后,,我们先引入的先被使用,先引用,先使用!
九、与vuex的区别
vuex:用来做状态管理的,里面定义的变量在每个组件中均可以使用和修改,在任一组件中修改此变量的值之后,其他组件中此变量的值也会随之修改。
Mixins:可以定义共用的变量,在每个组件中使用,引入组件中之后,各个变量是相互独立的,值的修改在组件中不会相互影响。
十、与公共组件的区别
组件:在父组件中引入组件,相当于在父组件中给出一片独立的空间供子组件使用,然后根据props来传值,但本质上两者是相对独立的。
Mixins:则是在引入Mixins之后,Mixins与组件中的属性和方法进行合并,相当于扩展了父组件的对象与方法,可以理解为形成了一个新的组件。
😄😄
另外,vue不建议,子组件直接修改props接收到的父组件的数据,但是,混入可以做到组件的属性或者方法覆盖混入对象的
混入的应用场景
假设我们需要在每个组件上添加name和time。在created、destroyed时,打出提示,并给出存活时间。
一共有五个组件,请问怎么做?
做法1:给每个组件添加data和created, destroyed钩子,重复5次
做法2:使用mixin减少重复。
做法1:
<template>
<div>child1</div>
</template>
<script>
export default{
data(){
return {
name:'child1',
time_birth:undefined,
time_dead:undefined
}
},
created(){
this.time_birth=new Date();
console.log(this.name+'出生了');
},
beforeDestroy(){
this.time_dead=new Date();
console.log(`${this.name}死了,共存活了${this.time_dead-this.time_birth}ms`);
}
}
</script>
// 依次对组件2 3 4 5 分别执行这些操作。。。
做法1小结: 代码重复太多,基本上每个组件都在复刻第一个组件的样式,这样下来,代码的维护性是十分低的。万一有一天要改需求了怎么办?又倒回去重新修改5次吗?5次并不是真正的5次,万一是10次,100次呢?很显然,这种做法并不可取。接下来来看另外一种做法。
做法2:
创建混入对象:
const myMixin = {
data(){
return {
/* 每个组件的名字不同,用另外的方法赋值。即每个组件自己带上自己的名字即可。 */
name:undefined,
time_birth:undefined,
time_dead:undefined
}
},
created(){
if(!this.name){
throw new Error('need name'); // 名字是用的组件里data的name
}
this.time_birth=new Date();
console.log(this.name+'出生了');
},
beforeDestroy(){
this.time_dead=new Date();
console.log(`${this.name}死了,共存活了${this.time_dead-this.time_birth}ms`);
}
}
export default myMixin;
组件里
<template>
<div>child1</div>
</template>
<script>
/* 首先导入公共部分的js内容 */
import myMixin from './Mixins/public.js';
export default{
data(){
return {
/* 其他组件就写自己组件的名字即可 */
name:'child1',
}
},
/* 使用导入的public模块 */
mixins:[myMixin],
}
</script>
用了混入后,组件只需要引用混入对象,然后在data里填写组件的名字,再挂载一下混入对象,就好了。
今天就聊到这里,后续有想到栗子再补充吧 🤭
🤭