學(xué)習(xí)vue2.5源碼之第四篇——GlobalAPI

Global-api——綁定全局配置和API

回顧一下src/core/index.js文件

import Vue from './instance/index'
import { initGlobalAPI } from './global-api/index'
import { isServerRendering } from 'core/util/env'

initGlobalAPI(Vue)

Object.defineProperty(Vue.prototype, '$isServer', {
  get: isServerRendering
})

Object.defineProperty(Vue.prototype, '$ssrContext', {
  get () {
    /* istanbul ignore next */
    return this.$vnode && this.$vnode.ssrContext
  }
})

Vue.version = '__VERSION__'

export default Vue

我們注意到了initGlobalAPI(Vue),說(shuō)明我們?cè)谝肰ue的時(shí)候在這里給Vue初始化了一些全局的配置和API,我們?cè)龠M(jìn)到global-api看看具體定義了哪些配置和API。

global-api/index.js

import config from '../config'
import { initUse } from './use'
import { initMixin } from './mixin'
import { initExtend } from './extend'
import { initAssetRegisters } from './assets'
import { set, del } from '../observer/index'
import { ASSET_TYPES } from 'shared/constants'
import builtInComponents from '../components/index'

import {
  warn,
  extend,
  nextTick,
  mergeOptions,
  defineReactive
} from '../util/index'

export function initGlobalAPI (Vue: GlobalAPI) {
  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是一個(gè)對(duì)象,包含 Vue 的全局配置
  Object.defineProperty(Vue, 'config', configDef)

  // util方法盡量別碰
  Vue.util = {
    warn,
    extend,
    mergeOptions,
    defineReactive
  }

  // 綁定全局API——Vue.set,Vue.delete,Vue.nextTick
  Vue.set = set
  Vue.delete = del
  Vue.nextTick = nextTick

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

  Vue.options._base = Vue

  extend(Vue.options.components, builtInComponents)

  // 初始化Vue.extend,Vue.mixin,Vue.extend
  // AssetRegisters就是component,directive,filter三者
  initUse(Vue)
  initMixin(Vue)
  initExtend(Vue)
  initAssetRegisters(Vue)
}

大概的理解都寫(xiě)在了注釋里,都是一些我們平時(shí)熟知的一些API,感興趣的話我們可以逐一去看,都不難理解。

global-api/use.js

export function initUse (Vue: GlobalAPI) {
  Vue.use = function (plugin: Function | Object) {
    const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))
    if (installedPlugins.indexOf(plugin) > -1) {
      return this
    }

    // 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
  }
}

這個(gè)方法定義了Vue.use的使用,看懂了這個(gè)對(duì)我們之后直接寫(xiě)Vue插件很有幫助哦~這個(gè)方法為Vue.use定義了兩種使用方法。第一種就是你寫(xiě)的插件(plugin參數(shù))是一個(gè)對(duì)象,然后Vue.use會(huì)找到這個(gè)對(duì)象中的install方法作為入口調(diào)用,第二種就是你傳來(lái)的參數(shù)就是一個(gè)函數(shù),然后直接執(zhí)行這個(gè)函數(shù)。當(dāng)install方法被同一個(gè)插件多次調(diào)用,插件將只會(huì)被安裝一次。

global-api/mixin.js

export function initMixin (Vue: GlobalAPI) {
  Vue.mixin = function (mixin: Object) {
    this.options = mergeOptions(this.options, mixin)
    return this
  }
}

mixin沒(méi)啥好說(shuō)的,就是將你傳來(lái)的參數(shù)對(duì)象和vue實(shí)例的選項(xiàng)實(shí)行合并策略。

global-api/extend.js

export function initExtend (Vue: GlobalAPI) {
  Vue.cid = 0
  let cid = 1

  Vue.extend = function (extendOptions: Object): Function {
    extendOptions = extendOptions || {}
    const Super = this
    const SuperId = Super.cid
    const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})
    if (cachedCtors[SuperId]) {
      return cachedCtors[SuperId]
    }

    const name = extendOptions.name || Super.options.name

    const Sub = function VueComponent (options) {
      this._init(options)
    }
    Sub.prototype = Object.create(Super.prototype)
    Sub.prototype.constructor = Sub
    Sub.cid = cid++
    Sub.options = mergeOptions(
      Super.options,
      extendOptions
    )
    Sub['super'] = Super

    if (Sub.options.props) {
      initProps(Sub)
    }
    if (Sub.options.computed) {
      initComputed(Sub)
    }

    Sub.extend = Super.extend
    Sub.mixin = Super.mixin
    Sub.use = Super.use

    ASSET_TYPES.forEach(function (type) {
      Sub[type] = Super[type]
    })
    if (name) {
      Sub.options.components[name] = Sub
    }

    Sub.superOptions = Super.options
    Sub.extendOptions = extendOptions
    Sub.sealedOptions = extend({}, Sub.options)

    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])
  }
}

首先是給Vue一個(gè)cid為0,之后創(chuàng)建的子類cid會(huì)不斷遞增。然后是給父類和子類之間的關(guān)系綁定,這是JavaScript原型鏈的一些基本方法,感受到再大型的框架都是從基本的基礎(chǔ)知識(shí)開(kāi)始搭建起的~之后是為子類初始化并進(jìn)行父選項(xiàng)和傳入的子選項(xiàng)進(jìn)行合并,我們看看子類得到了什么屬性

Sub.cid 
Sub.options
Sub.extend
Sub.mixin
Sub.use
Sub.component
Sub.directive
Sub.filter
// 新增的
Sub.super  // 父類
Sub.superOptions // 父類選項(xiàng)
Sub.extendOptions  // 傳入子類選項(xiàng)
Sub.sealedOptions // 子類目前的所有選項(xiàng)(父+自己)

global-api/assets.js

export function initAssetRegisters (Vue: GlobalAPI) {
  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
        return definition
      }
    }
  })
}

剛提到了資源ASSET_TYPES指的就是組件component,指令directive,過(guò)濾器filter這三個(gè)東東,

component

這個(gè)選項(xiàng)就是就將傳來(lái)的component作為子類繼承到父類Vue實(shí)例上,大概這樣用:

Vue.component('my-component', Vue.extend({ /* ... */ }))

directive

這個(gè)選項(xiàng)是為Vue實(shí)例添加指令,注冊(cè)后指令函數(shù)被 bindupdate 調(diào)用

filter

filter選項(xiàng)用于注冊(cè)或獲取全局過(guò)濾器。

// 注冊(cè)
Vue.filter('my-filter', function (value) {
  // 返回處理后的值
})

關(guān)于GlobalAPI的學(xué)習(xí)就到這里啦,大大小小的東西都過(guò)了一遍,應(yīng)該還蠻好理解的,有了這個(gè)更加深入的理解對(duì)我們使用全局API的時(shí)候會(huì)有很大幫助噢如有錯(cuò)誤之處請(qǐng)隨時(shí)提出謝謝~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Vue 實(shí)例 屬性和方法 每個(gè) Vue 實(shí)例都會(huì)代理其 data 對(duì)象里所有的屬性:var data = { a:...
    云之外閱讀 2,245評(píng)論 0 6
  • 這篇筆記主要包含 Vue 2 不同于 Vue 1 或者特有的內(nèi)容,還有我對(duì)于 Vue 1.0 印象不深的內(nèi)容。關(guān)于...
    云之外閱讀 5,082評(píng)論 0 29
  • 上一節(jié)我們結(jié)合代碼和文檔,詳細(xì)介紹了Global Config,下面我們?cè)敿?xì)來(lái)看看Global API。 Glob...
    小A家的銘閱讀 217評(píng)論 0 0
  • 親愛(ài)的,明天要記得給黃云輝發(fā)郵件,把IT風(fēng)險(xiǎn)抽查的內(nèi)容發(fā)給他。 然后合同整理好 mid表整理好 IP地址整理好 電...
    AnnaWT閱讀 191評(píng)論 0 0
  • 〈一〉 仰望月圓 月光永遠(yuǎn)也不會(huì)刺眼 可也不會(huì)溫暖 如果我們不曾擁抱在一起 又怎么會(huì)如今互相傷害 月光冷冷地凝視著...
    樓臺(tái)花舍閱讀 375評(píng)論 2 4