I used to think that mixins merge with components first, that is, if the content of mixins conflicts with components, the components prevail. Such a case does exist, but the policies specified by VUE are more detailed. The following are the merge strategies corresponding to each case
basic
When a component uses a mixin, all mixin options are mixed into the component’s own options
// define a mixin object
const myMixin = {
created() {
this.hello()
},
methods: {
hello() {
console.log('hello from mixin! ')}}}// define an app that uses this mixin
const app = Vue.createApp({
mixins: [myMixin]
})
app.mount('#mixins-basic') // => "hello from mixin!"
Copy the code
Option merge strategy
The options referred to here are data methods and lifecycle hook functions, which take different merge strategies
- like
data,methods,components,directives
Such items are merged into the same object, and the component’s conflicts prevail
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" }}})Copy the code
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"
Copy the code
- If there are hooks with the same name, they are merged together into an array and called one by one, and the mixin hook function is called first
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"
Copy the code
Global blending and customization options
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)
}
}
})
app.mount('#mixins-global') // => "hello!"
Copy the code
In the above code, we create a custom option globally, and then mix it globally, but note that this affects all the child components of the app:
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)
}
}
})
// add myOption also to child component
app.component('test-component', {
myOption: 'hello from component! '
})
app.mount('#mixins-global')
// => "hello!"
// => "hello from component!"
Copy the code
As we can see, this is not a simple substitution for the custom option, but a separate call, of course we can also make our own merge strategy:
const app = Vue.createApp({})
app.config.optionMergeStrategies.customOption = (toVal, fromVal) = > {
// return mergedVal
}
Copy the code
The merge policy takes two parameters, one is the value of the specified item in the parent instance and the child instance, so we can see what to print when using mixins:
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!"}})Copy the code
You can see the first print from mixin, and then print from app.
Matters needing attention
- Mixins are prone to conflicts, and you need to make sure you don’t have conflicting property names to avoid conflicts, which can create an additional burden
- Reusability is limited because mixins cannot accept parameters, so the logic is written and inflexible
So the official recommendation is to use the Composition Api to organize logic
Refer to the official documentation: Mixin