w3resource
Vue Tutorial

Mixins

Mixins are a flexible way by which reusable functionalities are distributed for Vue components. A mixin object could contain any component options. Whenever a component uses a mixin, all the options in the mixin will be "mixed" into the options of the component.

An example is as shown:

JS

// mixin object definition
```var myMixin = {
  created: function () {
    this.hello()
  },
  methods: {
    hello: function () {
      console.log('hello from mixin!')
    }
  }
}

// defining a component that uses this mixin
var Component = Vue.extend({
  mixins: [myMixin]
})

var component = new Component() // => "hello from mixin!"

Option Merging

Whenever a mixin and the component contain overlapping options, by the use of appropriate strategies they will be merged.

For instance, data objects can undergo a recursive merge, with the components data and takes priority in the case of conflicts.

JS

var mixin = {
  data: function () {
    return {
      message: 'hello',
      foo: 'abc'
    }
  }
}

new Vue({
  mixins: [mixin],
  data: function () {
    return {
      response: 'goodbye',
      bar: 'def'
    }
  },
  created: function () {
    console.log(this.$data)
    // => { response: "goodbye", foo: "abc", bar: "def" }
  }
})

Hook functions that have the same names are merged into an array so that all of them will be called. All mixin hooks will be called before the component's own hooks.

JS

var mixin = {
  created: function () {
    console.log('mixin hook called')
  }
}

new Vue({
  mixins: [mixin],
  created: function () {
    console.log('component hook called')
  }
})

// => "mixin hook is called"
// => "component hook is called"

For options that expect object values, for instance methods, directives and components, they will be merged into the same object. In this case the component's options will take priority when there are conflicting keys in these objects:

JS

var mixin = {
  methods: {
    foo: function () {
      console.log('foo')
    },
    conflicting: function () {
      console.log('from mixin')
    }
  }
}

var vm = new Vue({
  mixins: [mixin],
  methods: {
    bar: function () {
      console.log('bar')
    },
    conflicting: function () {
      console.log('from self')
    }
  }
})

vm.foo() // => "foo"
vm.bar() // => "bar"
vm.conflicting() // => "from self"

Note however that the same merge strategies are used in Vue.extend().

Global Mixin

We can equally apply a mixin globally. However, this should be used with caution! Once a mixin is applied globally, it will affect every Vue instance that is created afterwards. When this is used properly, it can be used to inject processing logic for custom options:

JS

Vue.mixin({
  created: function () {
    var myOption = this.$options.myOption
    if (myOption) {
      console.log(myOption)
    }
  }
})

new Vue({
  myOption: 'hello!'
})
// => "hello!"

HINT: you should use global mixins carefully and sparsely, this is because it affects every single Vue instance that is created, and that includes third party components. For the most case, you should only use it for custom option handling as demonstrated in the example above. Shipping them as plugins to avoid duplicate application is a good idea.

Custom Option Merge Strategies

When we merge custom options, they will use the default strategy which overwrites the existing value. If however we want a custom option to be merged using custom logic, we need to attach a function to vue.config.optionMergeStrategies:

JS

Vue.config.optionMergeStrategies.myOption = function (toVal, fromVal) {
  // return mergedVal
}

For options that are object-based, we can use the same strategy used by methods:

JS

var strategies = Vue.config.optionMergeStrategies
strategies.myOption = strategies.methods

Vuex's 1.x merging strategy provides a more advanced example:

JS

const merge = Vue.config.optionMergeStrategies.computed
Vue.config.optionMergeStrategies.vuex = function (toVal, fromVal) {
  if (!toVal) return fromVal
  if (!fromVal) return toVal
  return {
    getters: merge(toVal.getters, fromVal.getters),
    state: merge(toVal.state, fromVal.state),
    actions: merge(toVal.actions, fromVal.actions)
  }
}