preface

This week we will focus on the Vue global API

  • Vue.use
  • Vue.mixin
  • Vue.component
  • Vue.filter
  • Vue.directive
  • VUe.extend
  • Vue.set
  • Vue.delete
  • Vue.nextTick
The entrance

src/core/global-api/index.js

* Initialize Vue's global apis, such as: * Default configuration: Vue. Vue.util. Xx * Vue.set, vue.delete, vue.nexttick, vue.Observable * Vue.options.components, vue.options. directives, vue.options. Directives, vue.options. Filters, vue.options._base * Use, vue.extend, vue.mixin, vue.ponent, vue. directive, vue.filter * */ export function initGlobalAPI (Vue: GlobalAPI) { // config const configDef = {} configDef.get = () => config if (process.env.NODE_ENV ! == 'production') { configDef.set = () => { warn( 'Do not replace the Vue.config object, set individual fields instead.' ) } } // Vue.config Object.defineProperty(Vue, 'config', configDef) // 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} // vue. set/delete/nextTick Vue.set = set vue. delete = del vue. nextTick = nextTick // 2.6 explicit observable API Vue.observable = <>(obj: T): T => { observe(obj) return obj } 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 In Weex's multi-instance scenarios.vue.options. _base = Vue // Add a Vue.options.components for multi-instance scenarios Such as keep alive - the extend (Vue.options.com ponents, builtInComponents) // Vue.use initUse(Vue) // Vue.mixin initMixin(Vue) //Vue.extend initExtend(Vue) // Vue.component/directive/filter initAssetRegisters(Vue) }Copy the code
Vue.use

src/core/global-api/use.js

/** * define Vue. Use, which is responsible for installing a plugin for Vue. * 1. Check whether the plug-in has been installed. If the plug-in has been installed, finish it directly. * @param {*} plugin install method or object containing install method * @returns Vue instance */ export function initUse (Vue: GlobalAPI) { Vue.use = function (plugin: Function | Object) { const installedPlugins = (this._installedPlugins || (this._installedPlugins = [])) if (installedPlugins.indexOf(plugin) > -1) { return this }t // additional parameters const args = toArray(arguments, 1) args.unshift(this) if (typeof plugin.install === 'function') { plugin.install.apply(plugin, args) } else if (typeof plugin === 'function') { plugin.apply(null, args) } installedPlugins.push(plugin) return this } }Copy the code
Vue.mixin

src/core/global-api/mixin.js

/** * define Vue. Mixin, which is responsible for global blending options, affecting all Vue instances created later, * @param {*} mixin Vue configuration object * @returns Vue instance */ Vue. Mixin = function (mixin: Object) { this.options = mergeOptions(this.options, mixin) return this } }Copy the code
* 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 (process.env.NODE_ENV ! == 'production') { checkComponents(child) } if (typeof child === 'function') { child = child.options } normalizeProps(child, vm) normalizeInject(child, vm) normalizeDirectives(child) // Apply extends and mixins on the child options, // but only if it is a raw options object that isn't // the result of another mergeOptions call. // Only merged options has the _base property. if (! child._base) { 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) } } } const options = {} let key for (key in parent) { mergeField(key) } for (key in child) { if (! hasOwn(parent, key)) { mergeField(key) } } function mergeField (key) { const strat = strats[key] || defaultStrat options[key] = strat(parent[key], child[key], vm, key) } return options }Copy the code
Vue.component, vue.filter, vue.directive

These three apis are presented together

Create asset registration methods. * Define Vue.component, vue.filter, vue. directive. * These three methods do similar things, For example, Vue.component(compName, {xx}) as a result, this.options.components.com pName = component constructor * ASSET_TYPES = [' component ', 'directive, 'filter'] */ const ASSET_TYPES = ['component', 'directive', 'filter'] ASSET_TYPES.forEach(type => { Vue[type] = function ( id: string, definition: Function | Object ): Function | Object | void { if (! definition) { return this.options[type + 's'][id] } else { /* istanbul ignore if */ if (process.env.NODE_ENV ! == 'production' && type === 'component') { validateComponentName(id) } 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 return definition } } })Copy the code
Vue.extend

src/core/global-api/extend.js

/** * Each instance constructor, including Vue, has a unique * cid. This enables us to create wrapped "child * constructors" for prototypal inheritance and cache them. */ Vue. Cid = 0 let cid = 1 /** ** subclass inheritance */ ** ** Vue also has some default configurations * Default configurations are merged if they conflict with the base class (mergeOptions) * for example, we write JSX */ vue.extend = function (extendOptions: Object) in Vue: The Function {extendOptions = extendOptions | | {} const Super = this const SuperId = Super. Cid / * * * use of cache, If so, the constructor * is directly returned from the cache. When can this cache be used? * If you use the same configuration item (extendOptions) for multiple calls to vue.extend, This will enable the cache * / const cachedCtors = extendOptions. _Ctor | | (extendOptions. _Ctor = {}) if (cachedCtors [SuperId]) {return cachedCtors[SuperId] } const name = extendOptions.name || Super.options.name if (process.env.NODE_ENV ! == 'production' && name) { validateComponentName(name) } const Sub = function VueComponent (options) { this._init(options) } Sub.prototype = Object.create(Super.prototype) Sub.prototype.constructor = Sub Sub.cid = cid++ // Options merge, Sub.options = mergeOptions(super.options, extendOptions ) Sub['super'] = Super // For props and computed properties, we define the proxy getters on // the Vue instances at extension time, This // avoids object.defineProperty calls for each instance created. // Initialize computed, If (sub.options.props) {initProps(Sub)} if the component can be accessed using this.putedkey (Sub.options.computed) { initComputed(Sub) } // allow further extension/mixin/plugin usage Sub.extend = Super.extend Sub.mixin = Super.mixin Sub.use = Super.use // create asset registers, so extended classes // can have their private assets too. ASSET_TYPES.forEach(function (type) { Sub[type] = Super[type] }) // enable recursive self-lookup if (name) { Sub.options.components[name] = Sub } // keep a reference to the super options at extension time. // later at instantiation we can check if Super's options have // been updated. Sub.superOptions = Super.options Sub.extendOptions = extendOptions Sub.sealedOptions = extend({}, Sub.options) // cache constructor cachedCtors[SuperId] = Sub return Sub } } function initProps (Comp) { const props = Comp.options.props for (const key in props) { proxy(Comp.prototype, `_props`, key) } } function initComputed (Comp) { const computed = Comp.options.computed for (const key in computed) { defineComputed(Comp.prototype, key, computed[key]) } }Copy the code
Vue.set

src/core/global-api/index.js

Vue.set = set

set

src/core/observer/index.js

* Set a property on an object. Adds the new property and * triggers change notification if the property doesn't * Val * If the target is an object and the key does not already exist, then set the response to the new key. Then execute rely on notice * / export function set (target: Array < any > | Object, key: any, val: any) : any {the if (process. The env. NODE_ENV! == 'production' && (isUndef(target) || isPrimitive(target)) ) { warn(`Cannot set reactive property on undefined, null, or primitive value: ${(target: } (array, idx, val);} (array, idx, val); If (array.isArray (target) && isValidArrayIndex(key)) {target.length = math.max (target.length, Set (obj, key, val) if (key in target &&! (key in Object.prototype)) { target[key] = val return val } const ob = (target: any).__ob__ if (target._isVue || (ob && ob.vmCount)) { process.env.NODE_ENV ! == 'production' && warn( 'Avoid adding reactive properties to a Vue instance or its root $data ' + 'at runtime - declare  it upfront in the data option.' ) return val } if (! Ob) {target[key] = val return val} ob) {target[key] = val return val} DefineReactive (ob.value, key, val) ob.dep.notify() return val}Copy the code
Vue.delete

src/core/global-api/index.js

`Vue.delete = del

del

src/core/observer/index.js

* Delete a property and trigger change if necessary. * Delete the target object's array of specified keys by splice Method, the Object through the delete operator delete key is specified, and implement rely on notice * / export function del (target: Array < any > | Object, the key: any) { if (process.env.NODE_ENV ! == 'production' && (isUndef(target) || isPrimitive(target)) ) { warn(`Cannot delete reactive property on undefined, null, or primitive value: ${(target: any)}`) } if (Array.isArray(target) && isValidArrayIndex(key)) { target.splice(key, 1) return } const ob = (target: any).__ob__ if (target._isVue || (ob && ob.vmCount)) { process.env.NODE_ENV ! == 'production' && warn( 'Avoid deleting properties on a Vue instance or its root $data ' + '- just set it to null.' ) return } if (! hasOwn(target, key)) { return } delete target[key] if (! ob) { return } ob.dep.notify() }Copy the code
Vue.nextTick

You can see this in a future article

conclusion

Some of these apis are fairly common, and we need to not only know how to use them, but also understand the principles, so they are relatively useful.