preface

This article mainly handwritten Vue2.0 source code – global API principles

The last article we mainly introduced the principle of Vue computing attribute know the characteristics of computing attribute cache is how to achieve so far the core content of the entire Vue source code we have basically written again so this article to sort out the global API of Vue

Applicable group:

1. Want to deeply understand vUE source code better for daily business development

2. Want to write in the resume proficient vUE framework source code (no longer afraid of the interviewer’s serial kill question haha)

3. No time to see the official source code or first look at the source code feel difficult to understand the students


1 Vue.util

// src/global-api/index.js

// exposed util methods.
// NOTE: these are not considered part of the public API - avoid relying on
// them unless you are aware of the risk.
Vue.util = {
  warn,
  extend,
  mergeOptions,
  defineReactive,
};
Copy the code

Util is an internal Vue tool. It is not recommended to use business components because it may change with the version. If we do not develop third-party Vue plug-ins, it will be used less

2 Vue.set / Vue.delete

export function set(target: Array<any> | Object, key: any, val: any) :any {
  // We can refresh the view if we call splice directly from the array
  if (Array.isArray(target) && isValidArrayIndex(key)) {
    target.length = Math.max(target.length, key);
    target.splice(key, 1, val);
    return val;
  }
  // If it is a property of the object itself, add it directly
  if (key intarget && ! (keyin Object.prototype)) {
    target[key] = val;
    return val;
  }
  const ob = (target: any).__ob__;

  // If the object itself is not responsive, you do not need to define it as a responsive property
  if(! ob) { target[key] = val;return val;
  }
  DefineReactive = object.defineProperty = Object. DefineProperty = Object. DefineProperty = Object
  defineReactive(ob.value, key, val);
  ob.dep.notify(); // Notify view updates
  return val;
}
Copy the code
export function del(target: Array<any> | Object, key: any) {
  // Call splice if it is an array
  if (Array.isArray(target) && isValidArrayIndex(key)) {
    target.splice(key, 1);
    return;
  }
  const ob = (target: any).__ob__;
  // Do nothing if the object itself does not have this property
  if(! hasOwn(target, key)) {return;
  }
  // Delete this attribute directly with delete
  delete target[key];
  // Return directly if the object itself is not responsive
  if(! ob) {return;
  }
  ob.dep.notify(); // Notify view updates
}
Copy the code

These two apis are actually used in real business scenarios and there are a lot of set methods to add reactive data and delete methods to delete reactive data because the whole reactive process of Vue depends on the underlying API of Object.defineProperty but this API You can only hijack properties of objects that have been declared so that new properties are not reactive data and changing the array index directly does not cause view updates for performance reasons so we need to use $set and $delete to do that for those of you who are not familiar with the reactive principle see handwriting Vue2.0 Source code (a) – response data principle

3 Vue.nextTick

let callbacks = []; // The callback function
let pending = false;
function flushCallbacks() {
  pending = false; // Restore flag to false
  // Execute the callbacks in sequence
  for (let i = 0; i < callbacks.length; i++) { callbacks[i](); }}let timerFunc; // Start with a microtask and gracefully degrade the priority to implement asynchronous refresh
if (typeof Promise! = ="undefined") {
  // If promise is supported
  const p = Promise.resolve();
  timerFunc = () = > {
    p.then(flushCallbacks);
  };
} else if (typeofMutationObserver ! = ="undefined") {
  // MutationObserver is an asynchronous method that listens for dom changes
  let counter = 1;
  const observer = new MutationObserver(flushCallbacks);
  const textNode = document.createTextNode(String(counter));
  observer.observe(textNode, {
    characterData: true}); timerFunc =() = > {
    counter = (counter + 1) % 2;
    textNode.data = String(counter);
  };
} else if (typeofsetImmediate ! = ="undefined") {
  // If neither of the preceding supports setImmediate
  timerFunc = () = > {
    setImmediate(flushCallbacks);
  };
} else {
  // The last degradation is to use setTimeout
  timerFunc = () = > {
    setTimeout(flushCallbacks, 0);
  };
}

export function nextTick(cb) {
  // In addition to rendering watcher, the nextTick is collected into the array along with the user's own manual call
  callbacks.push(cb);
  if(! pending) {// If nextTick is called multiple times, the flag will be changed to false after the asynchronous queue is cleared
    pending = true; timerFunc(); }}Copy the code

NextTick is the core of Vue’s asynchronous update and this API is used very frequently in real business to get the properties of the DOM node immediately after the data is changed so you can put this method in nextTick to implement asynchronous update you can see handwriting Vue2.0 Source code (five) – asynchronous update principle

4 Vue.observable

Vue.observable = <T>(obj: T): T= > {
  observe(obj);
  return obj;
};
Copy the code

The core is to call the observe method to turn the incoming data into a reactive object that can be used to create global variables. The components share data with the observe method

5 Vue.options

Vue.options = Object.create(null);
ASSET_TYPES.forEach((type) = > {
  Vue.options[type + "s"] = Object.create(null);
});

// this is used to identify the "base" constructor to extend all plain-object
// components with in Weex's multi-instance scenarios.
Vue.options._base = Vue;

extend(Vue.options.components, builtInComponents); // Built-in components
Copy the code

Options is a container for component directives and filters and vue.options._base points to the Vue constructor

6 Vue.use

Vue.use = function (plugin: Function | Object) {
  const installedPlugins =
    this._installedPlugins || (this._installedPlugins = []);
  if (installedPlugins.indexOf(plugin) > -1) {
    // Return if the plugin was installed
    return this;
  }

  const args = toArray(arguments.1); // Get the parameter
  args.unshift(this); // Add the Vue constructor to the argument

  if (typeof plugin.install === "function") {
    plugin.install.apply(plugin, args); // Execute the install method
  } else if (typeof plugin === "function") {
    plugin.apply(null, args); // Execute the incoming plug-in without the install method
  }
  // Record the installed plug-ins
  installedPlugins.push(plugin);
  return this;
};
Copy the code

Use is mainly used to register plug-ins. It calls the install method of the plug-in and transfers its own Vue to the install method of the plug-in, so that third-party plug-ins can avoid strong dependence on Vue

7 Vue.mixin

export function initMixin(Vue: GlobalAPI) {
  Vue.mixin = function (mixin: Object) {
    this.options = mergeOptions(this.options, mixin); // just call mergeOptions to mergeOptions
    return this;
  };
}

/** * Merge two option objects into a new one. * Core utility used in both instantiation and inheritance. */
export function mergeOptions(
  parent: Object,
  child: Object, vm? : Component) :Object {
  if(! child._base) {// This means that the component needs to merge its own extends and mixins with its parent properties
    if (child.extends) {
      parent = mergeOptions(parent, child.extends, vm);
    }
    if (child.mixins) {
      for (let i = 0, l = child.mixins.length; i < l; i++) { parent = mergeOptions(parent, child.mixins[i], vm); }}}// Merge your own attributes with those of your father
  const options = {};
  let key;
  for (key in parent) {
    mergeField(key);
  }
  for (key in child) {
    if (!hasOwn(parent, key)) {
      mergeField(key);
    }
  }
  function mergeField(key) {
    // The actual method of merging fields
    const strat = strats[key] || defaultStrat; // The default merge policy is used if the default merge policy is not found
    options[key] = strat(parent[key], child[key], vm, key);
  }
  return options;
}
Copy the code

Mixin is a global mixin method commonly used to extract global public methods and attributes want to understand this section can see handwritten Vue2.0 source code (7) -Mixin mixin principle

8 Vue.extend

Vue.extend = function (extendOptions: Object) :Function {
  const Sub = function VueComponent(options) {
    // Create the subclass constructor and call the initialization method
    this._init(options);
  };
  Sub.prototype = Object.create(Super.prototype); // The subclass prototype points to the superclass
  Sub.prototype.constructor = Sub; //constructor refers to itself
  Sub.options = mergeOptions(
    // Merge your options with those of your parent class
    Super.options,
    extendOptions
  );
  return Sub;
};
Copy the code

Vue.extend creates components that rely on this API, called the component constructor Vue. In fact, it creates subclasses that inherit from Vue using prototype inheritance. For those interested in handwriting Vue2.0 source code (8) – Component Principles

9 Components, directives, and filters

export function initAssetRegisters(Vue: GlobalAPI) {
  var ASSET_TYPES = ["component"."directive"."filter"];
  /** * Create asset registration methods. */
  ASSET_TYPES.forEach((type) = > {
    Vue[type] = function (
      id: string,
      definition: Function | Object
    ) :Function | Object | void {
      if(! definition) {return this.options[type + "s"][id];
      } else {
        if (type === "component" && isPlainObject(definition)) {
          definition.name = definition.name || id;
          definition = this.options._base.extend(definition);
        }
        if (type === "directive" && typeof definition === "function") {
          definition = { bind: definition, update: definition };
        }
        this.options[type + "s"][id] = definition; // Put the component directive filter in vue.options
        returndefinition; }}; }); }Copy the code

Define the vue.componentVuue. Directive vue.filter API and format the user’s incoming content and put the result in vue.options

10 Global API mind map

summary

So far, Vue’s global API principle has been completed. Basically, a lot of code has been written in Vue’s principle series before. Many core apis are used frequently in daily development process and are also common test points in interviews Feel free to leave a comment if you have any questions or disputes

Finally, if you find this article helpful, remember to like it three times. Thank you very much!

Series of links (will be updated later)

  • Handwriting Vue2.0 source code (a) – response data principle
  • Handwriting Vue2.0 source code (2) – template compilation principle
  • Handwriting Vue2.0 source code (three) – initial rendering principle
  • Handwriting Vue2.0 source code (four) – rendering update principle
  • Handwriting Vue2.0 source code (five) – asynchronous update principle
  • Handwriting Vue2.0 source code (six) -diff algorithm principle
  • Handwriting Vue2.0 source code (seven) -Mixin Mixin principle
  • Handwriting Vue2.0 source code (eight) – component principle
  • Handwriting Vue2.0 source code (nine) – listening attribute principle
  • Handwriting Vue2.0 source code (ten) – the principle of computing attributes
  • Handwriting Vue2.0 source code (eleven) – global API principle
  • The most complete Vue interview questions + detailed answers
  • Handwritten vue-Router source code
  • Write vuex source code
  • Handwriting vue3.0 source code

Shark brother front touch fish technology group

Welcome technical exchanges within the fish can be pushed for help – link