🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# Mixins(混入) ## 基础 混入分发Vue组件可利用功能。一个混入的对象可以包含任意组件选项。当一个组件使用混入,所有选项都“混入”到组件自身选项中。 示例: ~~~ // 定义一个混入对象 const myMixin = { created() { this.hello() }, methods: { hello() { console.log('hello from mixin!') } } } // 使用混入定义一个应用 const app = Vue.createApp({ mixins: [myMixin] }) app.mount('#mixins-basic') // => "hello from mixin!" ~~~ ## 选项合并 当一个混入和组件自身包含相同选项时,它们会以一种合适的方式“合并”。 例如冲突的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" } } }) ~~~ 同名的勾子函数会被合并到一个数组中,所以它们都会被调用。混入的勾子函数会比组件自身的勾子函数先执行: ~~~ const myMixin = { created() { console.log('mixin hook called') } } const app = Vue.createApp({ mixins: [myMixin], created() { console.log('component hook called') } }) // => "mixin hook called" // => "component hook called" ~~~ 选项期望值是对象,例如`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" ~~~ ## 全局混入 你也可以为应用定义全局的混入: ~~~ 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!" ~~~ 谨慎使用!一旦你应用了一个全局混入,它将会影响整个应用的所有之后的组件实例创建(例如:子组件): ~~~ const app = Vue.createApp({ myOption: 'hello!' }) // inject a handler for `myOption` custom option`` 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!" ~~~ 在大部分情况下,你仅仅需要在定制选项上使用它,就像上面演示的例子。做为插件发布也是一个好主意,可以避免重复造轮子。 ## 自定义选项合并策略 当自定义选项合并时,将使用默认的策略决定覆盖值。如果你想根据自己的逻辑来决定合并策略,你需要同`app.config.optionMergeStrategies`函数一起使用: ~~~ const app = Vue.createApp({}) app.config.optionMergeStrategies.customOption = (toVal, fromVal) => { // 返回一个合并后的值 } ~~~ 合并策略分别通过第一个和第二个入参接收父子组件定义的选项值,让我们验证下使用混入时这些参数都是什么: ~~~ 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!" } }) ~~~ 正如所见,控制台首先打印混入的`toVal`和`fromVal`,然后才是应用。我们总是返回`fromVal`如果它被赋值,这就是为什么控制台最后会打印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!" } }) ~~~ ## 预防措施 在Vue2中,混入主要功能是抽取组件的逻辑部件到可复用的块中。但是有一些问题: * 混入容易起冲突:自各功能的属性合并到同一个组件,你仍然需要知道每一个其它功能来避免组件名冲突和调试。 * 复用是有限制的:我们不能传递任何参数到混入来改变逻辑,这会降低抽逻辑协议的适用性。 提出这些问题,我们增加了一个新的方式来组织逻辑点代码:组合API。