Vue 中 mixins(混入)的介绍和使用

发布于:2024-04-19 ⋅ 阅读:(31) ⋅ 点赞:(0)

目录

前言

什么是 mixins?

如何创建 mixins?

如何使用 mixins

mixins 的特点

方法和参数在各组件中不共享

mixins 与组件冲突

冲突之 合并+覆盖

冲突之 合并

全局 mixins

mixins 中有异步请求的情况

与 vuex 的区别

与公共组件的区别


前言

在项目开发的时候,常会碰到这样的一种现象:有两个组件非常相似,比如较为熟悉的 Modal 、 Tooltip 和 Popover ,它们都具有同样的基本函数,而且它们之间也有足够的不同。很多时候,就让人很难做出选择:是把它们拆会成多个不同的组件呢?还是只使用一个组件,创建足够的属性来改变不同的情况?

这些解决方案都不够完美。如果拆分成多个组件,就不得不冒着如果功能变动你要在多个文件中更新它的风险。另一方面,太多的属性会很快变得混乱,难维护,甚至对于组件开发者自已面言,也是件难事。

在Vue中,对于这样的场景,官方提供了一种叫混入 (mixins) 的特性。可以利用 mixins 将公共部分提取出来,使用 mixins 允许你封装一块在应用的其他组件中都可以使用的函数。如果被正确的使用,他们不会改变函数作用域外部的任何东西,所以多次执行,只要是同样的输入,总是能得到一样的值。

什么是 mixins?

混入 (mixins) 是一个 JavaScript 对象,可以包含任意组件选项,比如 Vue 实例中生命周期的各个钩子函数,也可以是 data 、components 、methods 或 directives 等。当组件使用混入对象时,所有混入对象的选项将被混合进入该组件本身的选项。

如何创建 mixins?

在 src 目录下创建一个 mixins 文件夹,在文件夹下新建一个 myMixins.js 文件。因为 mixins 是一个 js 对象,所以应该以对象的形式来定义 myMixins,在对象中可以和 vue 组件一样来定义 data、components、methods、created、computed 等属性,并通过 export 导出该对象。

如何使用 mixins

在需要调用的组件中引入 myMixins.js 文件,然后在 export default 中引入需要的对象即可。

<script>
import { myMixins } from "@/mixins/myMixins.js"
export default {
    mixins: [myMixins]
}
</script>

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中对 num 进行 +1 操作

import { myMixins } from "@/mixins/myMixins.js";
export default {
  mixins: [myMixins],
  data() {
    return {}
  },
  created() {
    this.age++
  },
}

③ 组件2不进行操作

export default {
  mixins: [myMixins],
  data() {
    return {}
  },
}

④ 我们分别切换到两个页面,查看控制台输出。

会发现组件1改变了 age 里面的值,组件2中 age 值还是混合对象的初始值,并没有随着组件1的增加而改变

mixins 与组件冲突
冲突之 合并+覆盖
  • 数据对象(data)在内部会进行递归合并
  • 值为对象(components、methods 、computed、directives)的选项将被合并为同一个对象。
  • 键冲突时优先组件即组件中的键会覆盖混入对象。

① 在混入对象增加 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 方法

冲突之 合并

watch选项、钩子函数混入组件时,选项会被合并到一个数组中,因此都会被执行。按照传入顺序依次调用,并在调用组件自身的钩子之前被调用。

// myMixins.js
export const myMixins = {
  components:{},
  data() {
    return {}
  },
  created() {
    console.log('xxx from mixins')
  }
}
import { myMixins } from "@/mixins/myMixins.js";
export default {
  mixins: [myMixins],
  data() {
    return {}
  },
  created() {
    console.log('xxx from template')
  }
}

全局 mixins

当我们使用全局混合时,我们不是指能够在每个组件上访问它们,就像是过滤器一样。我们能够通过  mixins:[myMixins]  访问组件上的混合对象。

全局混合被注册到了每个单一组件上。因此,它们的使用场景极其有限并且要非常的小心。一个我能想到的用途就是它像一个插件,你需要赋予它访问所有东西的权限。但即使在这种情况下,我也对你正在做的保持警惕,尤其是你在应用中扩展的函数,可能对你来说是不可知的

为了创建一个全局实例,我们可以把它放在 Vue 实例之上。在一个典型的 Vue-cli 初始化的项目中,它可能在你的  main.js  文件中。

Vue.mixin({
     mounted() {
         console.log('hello from mixin!')
     }
})

new Vue({
     ...
})

谨慎使用全局混入对象,因为会影响到每个单独创建的 Vue 实例 (包括第三方模板)。大多数情况下,只应当应用于自定义选项,就像上面示例一样。也可以将其用作 插件 以避免产生重复应用。

mixins 中有异步请求的情况

问题描述: 当混合里面包含异步请求函数,而我们又需要在组件中使用异步请求函数的返回值时,我们会取不到此返回值。如下:

// myMixins.js
export const myMixins = {
  components:{},
  data() {
    return {
      num: 1,
    }
  },
  methods: {
    getDate1() {
      new Promise((resolve,reject) => {
          let a = 1;
          setTimeout(() => {
            resolve(a)
          },500)
        }).then(res => {
          console.log(res,'res');
          return res
      })
    },
  }
}
// todo.vue
import { myMixins } from "./myMixins.js";

export default {
  mixins: [myMixins],
  data() {
    return {}
  },
  mounted() {
    console.log(this.getDate1,'template1-func_one')
  }
}

打印结果:undefined "template1-func_one"

解决方案:不要返回结果,而是直接返回异步函数

// myMixins.js
export const myMixins = {
  components:{},
  data() {
    return {
      num: 1,
    }
  },
  methods: {
   async getDate1() {
      let result = await new Promise((resolve,reject) => {
          let a = 1;
          setTimeout(() => {
            resolve(1)
          },500)
       })
       return result
    },
  }
}
// todo.vue
import { myMixins } from "./myMixins.js";

export default {
  mixins: [myMixins],
  data() {
    return {}
  },
  mounted() {
    this.getDate1().then(res => {
      console.log(res,'template1-res')
    })
  }
}

打印结果:1 "template1-res"

与 vuex 的区别

  • vuex: 用来做状态管理的,里面定义的变量在每个组件中均可以使用和修改,在任一组件中修改此变量的值之后,其他组件中此变量的值也会随之修改。
  • Mixins: 可以定义共用的变量,在每个组件中使用,引用组件中之后,各个变量是相互独立的,值的修改在组件中不会相互影响。

与公共组件的区别

  • 组件: 在父组件中引入组件,相当于在父组件中给出一片独立的空间供子组件使用,然后根据 prop 来传值,但本质上两者是相对独立的。
  • Mixins: 在引入组件之后与组件中的对象和方法进行合并,相当于扩展了父组件的对象与方法,可以理解为形成了一个新的组件。