Mixin 是一种,非常灵活的,分发 Vue 组件中,可复用功能的,方式。
mixin 对象可以包含任意组件选项。当组件使用 mixin 对象时,所有 mixin 对象的选项将被“混合”进入该组件本身的选项。
Mixin就是当你看到某个组件内的某些代码比较常用,就单独将它抽取出来,然后混入到别的组件内。
Mixin往往不是一个完整的组件,它可以是一些代码,也可以是一些选项。
例子:
// 定义一个 mixin 对象 const myMixin = { created() { this.hello() }, methods: { hello() { console.log('hello from mixin!') } } } // 定义一个使用此 mixin 对象的应用 const app = Vue.createApp({ mixins: [myMixin] }) app.mount('#mixins-basic') // => "hello from mixin!"
注意在使用mixins选项的时候,接收的是一个数组类型。
当组件和 mixin 对象含有同名选项时,Vue将以恰当的默认方式进行“合并”。
比如,每个 mixin 可以拥有自己的 data
函数。每个 data
函数都会被调用,并将返回结果合并。
在数据发生冲突时,会以组件自身的数据为优先。
也就是说,组件本身的data选项优先级更高!
const myMixin = { data() { return { message: 'hello', foo: 'abc' } } } const app = Vue.createApp({ mixins: [myMixin], data() { return { message: 'goodbye', bar: 'def' } }, created() { console.log(this.$data) // => { message: "goodbye", foo: "abc", bar: "def" } } })
同名钩子函数将合并为一个数组,因此都将被调用。
并且,mixin 对象的钩子将在组件自身钩子之前调用。
也就是说,同名的钩子函数不会冲突,都会执行,但先执行mixin的。
const myMixin = { created() { console.log('mixin 对象的钩子被调用') } } const app = Vue.createApp({ mixins: [myMixin], created() { console.log('组件钩子被调用') } }) // => "mixin 对象的钩子被调用" // => "组件钩子被调用"
值为对象的选项,例如 methods
、components
和 directives
,将被合并为同一个对象。
两个对象键名冲突时,取组件对象的键值对。
const myMixin = { methods: { foo() { console.log('foo') }, conflicting() { console.log('from mixin') } } } const app = Vue.createApp({ mixins: [myMixin], methods: { bar() { console.log('bar') }, conflicting() { console.log('from self') } } }) const vm = app.mount('#mixins-basic') vm.foo() // => "foo" vm.bar() // => "bar" vm.conflicting() // => "from self"
前面是组件私有的mixin。
还可以为 Vue 应用程序全局应用 mixin:
const app = Vue.createApp({ myOption: 'hello!' }) // 为自定义的选项 'myOption' 注入一个处理器。 app.mixin({ created() { const myOption = this.$options.myOption if (myOption) { console.log(myOption) } } }) app.mount('#mixins-global') // => "hello!"
一旦注册了全局 mixin,它将影响每一个之后创建的组件,所以使用时需格外小心!看下面的例子:
const app = Vue.createApp({ myOption: 'hello!' }) // 为自定义的选项 'myOption' 注入一个处理器。 app.mixin({ created() { const myOption = this.$options.myOption if (myOption) { console.log(myOption) } } }) // 将myOption也添加到子组件 app.component('test-component', { myOption: 'hello from component!' }) app.mount('#mixins-global') // => "hello!" // => "hello from component!"
假如你在组件中自定义了选项,然后又使用了mixin,mixin中也有这个自定义的选项,那么在两者合并时,默认策略为简单地覆盖已有值。
如果想让某个自定义选项以自定义逻辑进行合并,可以在 app.config.optionMergeStrategies
中添加一个函数:
const app = Vue.createApp({}) app.config.optionMergeStrategies.customOption = (toVal, fromVal) => { // return mergedVal }
合并策略接收在父实例和子实例上定义的该选项的值,分别作为第一个和第二个参数。
让我们来看看使用 mixin 时,这些参数有哪些:
const app = Vue.createApp({ custom: 'hello!' }) app.config.optionMergeStrategies.custom = (toVal, fromVal) => { console.log(fromVal, toVal) // => "goodbye!", undefined // => "hello", "goodbye!" return fromVal || toVal } app.mixin({ custom: 'goodbye!', created() { console.log(this.$options.custom) // => "hello!" } })
如你所见,在控制台中,我们先从 mixin 打印 toVal
和 fromVal
,然后从 app
打印。如果存在,我们总是返回 fromVal
,这就是为什么 this.$options.custom
设置为 hello!
最后。让我们尝试将策略更改为始终从子实例返回值:
const app = Vue.createApp({ custom: 'hello!' }) app.config.optionMergeStrategies.custom = (toVal, fromVal) => toVal || fromVal app.mixin({ custom: 'goodbye!', created() { console.log(this.$options.custom) // => "goodbye!" } })
在 Vue 2 中,mixin 是将部分组件逻辑抽象成可重用块的主要工具。但是,这有几个问题:
为了解决这些问题,Vue使用逻辑关注点组织代码的新方法:组合式 API。