This is the 27th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021

Vue.mixin is an excellent API when used properly, but it can be a nightmare when abused or used improperly, which is why it is officially not recommended to be used in application projects. Although it has some disadvantages, such as naming conflicts and source confusion, it does not prevent us from exploring its principles

So let’s see how it works. Now we have this code, right

import Vue from "vue";

Vue.mixin({
  created: function () {
    console.log("mixins created"); }});new Vue({
  created() {
    console.log("Instance created"); }});Copy the code

Mixins will merge internal created and component created, and the console will output mixins created and instance created

Vue.mixin

When initGlobalAPI is called for global API initialization above, initMixin(Vue) is called internally for global API registration of mixin, and the code is as follows: Omit irrelevant code

export function initGlobalAPI(Vue) {
  // Integrate all globally relevant content
  Vue.options = Object.create(null);
  initMixin(Vue);
}
Copy the code

The code for registering global mixins is as follows: not much is done internally, and the actions of the mergeOptions are all abstracted into the mergeOptions function

export function initMixin (Vue) {
  Vue.mixin = function (mixin) {
    this.options = mergeOptions(this.options, mixin)
    return this}}export function mergeOptions(parent, child){
  // todo...
}
Copy the code

In mixins, the essence is the merging of the parent and child options, which is essentially the merging of two objects

Iterate over parent and child

/ / traverse the parent
for (const key in parent) {
  mergeField(key);
}

/ / iterate through the child
for (const key in child) {
  // If you have already merged, you do not need to merge again
  if (!parent.hasOwnProperty(key)) {
    mergeField(key);
  }
}
Copy the code

The specific merge strategy is encapsulated in the mergeField function. Before writing the logic, let’s review how mixins merge options with the same name

  1. The hook function of the same name will be merged into an array, so both will be called. In addition, hooks mixed in with objects are called before the component’s own hooks. Like the life cycle
  2. Value is an option for the object, for examplemethods,componentsdirectivesWill be merged into the same object. When two object key names conflict, the component object’s key-value pair is taken.

Mixins use different merge methods for different situations, so let’s first look at what merge is for objects, which is the default merge strategy

function mergeField(key) {
  // all are objects
  if (typeof parent[key] === "object" && typeof child[key] === "object") {
    // The key name conflicts with the parentoptions[key] = { ... parent[key], ... child[key], }; }else if (child[key] === null) {
    // Use parent
    options[key] = parent[key];
  } else {
    // Use child as the standardoptions[key] = child[key]; }}Copy the code

Special handling is required for hook merges of the same name, such as life cycle merges

Start by defining the entire lifecycle

const LIFECYCLE_HOOKS = [
  "beforeCreate"."created"."beforeMount"."mounted"."beforeUpdate"."updated"."beforeDestroy"."destroyed",];Copy the code

Lifecycle hook merges are the same, so you can traverse LIFECYCLE_HOOKS to define the behavior of each hook

function mergeHook(parentVal, childVal) {
  const res = childVal
    ? parentVal
      ? parentVal.concat(childVal) // Parent child is an array
      : Array.isArray(childVal)
      ? childVal
      : [childVal]
    : parentVal; // Use the old child directly
    
  return res ? dedupeHooks(res) : res;
}

/** * Delete duplicate data */
function dedupeHooks(hooks) {
  const res = [];
  for (let i = 0; i < hooks.length; i++) {
    if (res.indexOf(hooks[i]) === -1) { res.push(hooks[i]); }}return res;
}

// Iterate through all lifecycle hooks
LIFECYCLE_HOOKS.forEach(hook= > {
  strats[hook] = mergeHook
})
Copy the code

In Vue.mixin there are special treatments for components, directives, filters, etc