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
- 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
- Value is an option for the object, for example
methods
,components
和directives
Will 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