欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

vue2源碼解析之全局API實例詳解

 更新時間:2022年11月01日 13:11:46   作者:1undefined2  
全局API并不在構造器里,而是先聲明全局變量或者直接在Vue上定義一些新功能,Vue內(nèi)置了一些全局API,下面這篇文章主要給大家介紹了關于vue2源碼解析之全局API的相關資料,需要的朋友可以參考下

前言

實例方法是掛載在vue的原型上,而全局方法是掛載在vue上;全局方法有12個,分別為extend、nextTick、set、delete、directive、filter、component、use、mixin、version和observable;

Vue.extend()

基本使用

/*
作用:
使用基礎vue構造器,創(chuàng)建一個子類,參數(shù)是一個包含組件選項的對象
`data` 選項是特例,需要注意 - 在 `Vue.extend()` 中它必須是函數(shù)
*/
Vue.extend(options)

// eg:
<div id="mount-point"></div>
// 創(chuàng)建構造器  
var Profile = Vue.extend({  
    template: '<p>{{firstName}} {{lastName}} aka {{alias}}</p>',  
    data: function () {  
        return {  
            firstName: 'Walter',  
            lastName: 'White',  
            alias: 'Heisenberg'  
        }  
    }  
})  
// 創(chuàng)建 Profile 實例,并掛載到一個元素上。  
new Profile().$mount('#mount-point')

// 結果:
<p>Walter White aka Heisenberg</p>

整體源碼

// 源碼位置 src/core/global-api/extend.js
 Vue.extend = function (extendOptions: Object): Function {
    // 初始化參數(shù)
    extendOptions = extendOptions || {}
    // 存儲父類
    const Super = this
    // 存儲父類的唯一標識
    const SuperId = Super.cid
    // 獲取到參數(shù)中的緩存數(shù)據(jù)
    const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})
    // 如果已經(jīng)緩存過就會緩存中獲取返回
    if (cachedCtors[SuperId]) {
      return cachedCtors[SuperId]
    }
    // 獲取到name
    const name = extendOptions.name || Super.options.name
    if (process.env.NODE_ENV !== 'production' && name) {
      validateComponentName(name)
    }
    // 創(chuàng)建一個子類
    const Sub = function VueComponent (options) {
      this._init(options)
    }
    // 原型繼承
    Sub.prototype = Object.create(Super.prototype)
    // 修改構造器
    Sub.prototype.constructor = Sub
    // 子類的唯一標識
    Sub.cid = cid++
    // 合并父類和傳遞進來的參數(shù)
    Sub.options = mergeOptions(
      Super.options,
      extendOptions
    )
    // 子類中存儲父類
    Sub['super'] = Super

    // 如果子類中有props 進行初始化
    if (Sub.options.props) {
      initProps(Sub)
    }
    // 如果子類中有計算屬性,進行初始化
    if (Sub.options.computed) {
      initComputed(Sub)
    }

    // 把父類的extend,mixin,use放在子類上
    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)

    // cache constructor
    // 緩存子類
    cachedCtors[SuperId] = Sub
    return Sub
  }
}

// 把子類中的props存儲到原型上
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])
  }
}

extend方法內(nèi)部其實就是創(chuàng)建一個子類,通過原型繼承的方式繼承父類,然后把父類的屬性和一些方法存儲到子類上,并且把子類進行緩存,再一開始就先從緩存中獲取子類,如果沒有就進行屬性和方法的繼承,最后返回子類;

Vue.nextTick,Vue.set,Vue.delete

以上三種都在實例方法中解析過

Vue.directive、Vue.filter、Vue.component

基本使用

注冊或獲取全局指令

// 注冊  
Vue.directive('my-directive', {  
    bind: function () {},  
    inserted: function () {},  
    update: function () {},  
    componentUpdated: function () {},  
    unbind: function () {}  
})  
  
// 注冊 (指令函數(shù))  
Vue.directive('my-directive', function () {  
// 這里將會被 `bind` 和 `update` 調用  
})  
  
// getter,返回已注冊的指令  
var myDirective = Vue.directive('my-directive')

注冊或獲取過濾器

// 注冊
Vue.filter('my-filter',function(){})
// 獲取
Vue.filter('my-filter')

注冊或獲取組件

// 注冊 傳入一個擴展過的構造器
Vue.component('my-component', Vue.extend({}))
// 注冊 傳入一個選項對象
Vue.component('my-component', {})
// 獲取
Vue.component('my-component')

源碼分析

// 源碼位置 src/core/global-api/
export const ASSET_TYPES = [
  'component',
  'directive',
  'filter'
]

export function initAssetRegisters (Vue: GlobalAPI) {
  /**
   * Create asset registration methods.
   */
  ASSET_TYPES.forEach(type => {
    Vue[type] = function (
      id: string,
      definition: Function | Object
    ): Function | Object | void {
      // 不存在definition 表示獲取,直接從options下的相應的typs+'s'進行獲取
      if (!definition) {
        return this.options[type + 's'][id]
      } else {
        /* istanbul ignore if */
        if (process.env.NODE_ENV !== 'production' && type === 'component') {
          validateComponentName(id)
        }
        // 如果是組件 并且definition為一個{}對象,那么就通過extend繼承vue
        if (type === 'component' && isPlainObject(definition)) {
          // 沒有name就使用id
          definition.name = definition.name || id
          // 使definition繼承vue
          definition = this.options._base.extend(definition)
        }
        // 如果是指令并且definition是一個函數(shù),那么就把這個函數(shù)作為bind和update
        if (type === 'directive' && typeof definition === 'function') {
          definition = { bind: definition, update: definition }
        }
        // 設置值 保存到對應的key下
        this.options[type + 's'][id] = definition
        return definition
      }
    }
  })
}

指令,過濾器,組件把它們放在一個數(shù)組中,遍歷這個數(shù)組,分別進行處理

export const ASSET_TYPES = [
  'component',
  'directive',
  'filter'
]
 ASSET_TYPES.forEach(type => {
    Vue[type] = function (
      id: string,
      definition: Function | Object
    ){}
 })

如果沒有傳遞第二個參數(shù),表示是獲取,直接進行獲取返回

if (!definition) {
    return this.options[type + 's'][id]
}

否則就是傳遞了第二個參數(shù),表示是注冊,首先判斷是否是組件,是組件并且第二個參數(shù)是對象,那么就繼承Vue;

// 如果是組件
if (type === 'component' && isPlainObject(definition)) {
  // 沒有name就使用id
  definition.name = definition.name || id
  // 使definition繼承vue
  definition = this.options._base.extend(definition)
}

如果是指令,并且第二個參數(shù)是函數(shù),那么直接放在一個對象中

// 如果是指令
if (type === 'directive' && typeof definition === 'function') {
  definition = { bind: definition, update: definition }
}

最后給相應的對象下的自定義指令或過濾器或組件進行賦值并返回

// 設置值
this.options[type + 's'][id] = definition
return definition

通過以上三種方法就可以自定義組件,過濾器和指令,然后就可以在模板中使用它們,最終的處理還是在模板編譯節(jié)點進行的;

Vue.use

基本使用

/*
作用:
安裝 Vue.js 插件。如果插件是一個對象,必須提供 `install` 方法。
如果插件是一個函數(shù),它會被作為 install 方法。install 方法調用時,會將 Vue 作為參數(shù)傳入。
該方法需要在調用 `new Vue()` 之前被調用。
當 install 方法被同一個插件多次調用,插件將只會被安裝一次
plugin:-   `{Object | Function} plugin`
*/
Vue.use( plugin )

源碼預覽

// 源碼位置 src/core/global-api/use.js
export function initUse (Vue: GlobalAPI) {
  Vue.use = function (plugin: Function | Object) {
    // 初始_installedPlugins變量
    const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))
    // 如果已經(jīng)存在直接返回
    if (installedPlugins.indexOf(plugin) > -1) {
      return this
    }

    // 獲取剩余的參數(shù)轉成數(shù)組
    const args = toArray(arguments, 1)
    // 把this添加進去
    args.unshift(this)
    // 如果install是一個函數(shù) 直接執(zhí)行
    if (typeof plugin.install === 'function') {
      plugin.install.apply(plugin, args)
    } else if (typeof plugin === 'function') { // 如果插件是一個函數(shù),直接執(zhí)行
      plugin.apply(null, args)
    }
    // 添加到數(shù)組中
    installedPlugins.push(plugin)
    return this
  }
}

首先獲取到用來緩存的屬性,如果不存在初始化為一個數(shù)組,再判斷傳遞進來的插件是否已經(jīng)存在,存在表示重復操作,直接返回;(實現(xiàn):當 install 方法被同一個插件多次調用,插件將只會被安裝一次)

// 初始_installedPlugins變量
    const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))
// 如果已經(jīng)存在直接返回
if (installedPlugins.indexOf(plugin) > -1) {
  return this
}

接著獲取到剩余的參數(shù),并且把當前實例也作為參數(shù)(實現(xiàn):install 方法調用時,會將 Vue 作為參數(shù)傳入。)

// 獲取剩余的參數(shù)轉成數(shù)組
const args = toArray(arguments, 1)
// 把this添加進去
args.unshift(this)

判斷plugin.install是否是一個函數(shù),如果是函數(shù)就通過plugin執(zhí)行(實現(xiàn):如果插件是一個對象,必須提供 install 方法)

// 如果install是一個函數(shù) 直接執(zhí)行
if (typeof plugin.install === 'function') {
  plugin.install.apply(plugin, args)
}

否則plugin是一個函數(shù),那么直接執(zhí)行(實現(xiàn):如果插件是一個函數(shù),它會被作為 install 方法)

else if (typeof plugin === 'function') { // 如果插件是一個函數(shù),直接執(zhí)行
  plugin.apply(null, args)
}

最后添加到緩存中并返回

// 添加到數(shù)組中
installedPlugins.push(plugin)
return this

Vue.mixin

基本使用

/*
作用:
全局注冊一個混入,影響注冊之后所有創(chuàng)建的每個vue實例,插件作者可以使用混入,
向組件注入自定義的行為。**不推薦在應用代碼中使用**。
*/
Vue.mixin()

源碼預覽

// 源碼位置 src/core/global-api/mixin.js
export function initMixin (Vue: GlobalAPI) {
  Vue.mixin = function (mixin: Object) {
    this.options = mergeOptions(this.options, mixin)
    return this
  }
}

混入很簡單,就是把傳遞進來的數(shù)據(jù)和實例上已有的數(shù)據(jù)進行合并替換,最后重新賦值給實例上的options;

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
  }
  // 設置props,把帶有-的屬性名改成駝峰,存到一個新的對象中進行返回
  normalizeProps(child, vm)
  // 設置注入的屬性 把inject中的數(shù)據(jù)都轉成 {from:val}形式的對象返回
  normalizeInject(child, vm)
  // 設置指令 返回指令的值為{ bind: def, update: def }的形式
  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.
  // 遞歸處理extends和mixins
  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)
      }
    }
  }
  // 創(chuàng)建一個新的對象
  const options = {}
  let key
  for (key in parent) { // 遍歷父級進行設置屬性
    mergeField(key)
  }
  for (key in child) { // 遍歷子級進行設置屬性
    if (!hasOwn(parent, key)) { // 父級不存在此屬性就進行設置
      mergeField(key)
    }
  }
  // 通過策略模式給不同的屬性設置對應的執(zhí)行函數(shù),
  function mergeField (key) {
    // 獲取到不同屬性的函數(shù)
    const strat = strats[key] || defaultStrat
    // 執(zhí)行對應的函數(shù)重新設置屬性
    options[key] = strat(parent[key], child[key], vm, key)
  }
  return options
}

把子級的屬性進行單獨處理,處理完成之后和父級的屬性進行合并,合并之后進行返回;

Vue.compile

基本使用

/*
作用: 將一個模板字符串編譯成 render 函數(shù)。**只在完整版時可用**。
template: 字符串模板
*/
Vue.compile(template)

源碼預覽

Vue.compile = compileToFunctions

compileToFunctions函數(shù)在模板編譯節(jié)點已經(jīng)解析完

Vue.observable

基本用法

/*
作用:
讓一個對象可響應,Vue內(nèi)部會用它來處理data函數(shù)返回的對象
返回的對象可以直接用于[渲染函數(shù)]和[計算屬性]內(nèi),并且會在發(fā)生變更時觸發(fā)相應的更新。
也可以作為最小化的跨組件狀態(tài)存儲器,用于簡單的場景:
*/
const state = Vue.observable({ count: 0 })  
const Demo = {  
    render(h) {  
        return h('button', {  
            on: { click: () => { state.count++ }}  
        }, `count is: ${state.count}`)  
    }  
}

源碼預覽

// 源碼位置 src/core/global-api/
// 2.6 explicit observable API
Vue.observable = <T>(obj: T): T => {
    observe(obj)
    return obj
}

總結

extend: 內(nèi)部實現(xiàn)一個子類,通過原型繼承的方式繼承自當前調用者(父類),并且把父類中的屬性進行合并,存儲到自己的options中,父類的方法添加到自己構造器上;把子類進行緩存;一進入到函數(shù)內(nèi)部首先從緩存中獲取,沒有才進行創(chuàng)建子類;

directive,filter,component: 這三種方式通過一個函數(shù)實現(xiàn),首先判斷有沒有傳遞第二個參數(shù),如果沒傳遞表示是獲取,直接獲取返回;如果有傳遞表示注冊,如果是指令并且第二個參數(shù)是函數(shù),那么把函數(shù)作為bind和update的值;如果是組件并且第二個參數(shù)是函數(shù),那么通過extend方法進行繼承;

use: 如果緩存中有此插件就直接返回,否則就判斷傳遞進來的參數(shù)是對象還是函數(shù),如果是對象那么就執(zhí)行對象上的install方法,如果是函數(shù)直接執(zhí)行;并且把當前實例作為參數(shù)傳遞進去;最后把插件進行緩存;

mixin: 首先把props,inject和指令的屬性進行統(tǒng)一格式化操作;然后把當前實例的options和傳遞進來的參數(shù)進行合并,相同屬性傳遞進來的參數(shù)會覆蓋options中的屬性;

observable: 通過調用observe給當前傳遞進來的對象添加響應式,并且返回該對象;

到此這篇關于vue2源碼解析之全局API實例詳解的文章就介紹到這了,更多相關vue2全局API內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • vant中的picker選擇器自定義選項內(nèi)容

    vant中的picker選擇器自定義選項內(nèi)容

    這篇文章主要介紹了vant中的picker選擇器自定義選項內(nèi)容,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • vue學習筆記之給組件綁定原生事件操作示例

    vue學習筆記之給組件綁定原生事件操作示例

    這篇文章主要介紹了vue學習筆記之給組件綁定原生事件操作,結合實例形式詳細分析了vue.js組件綁定原生事件相關原理、實現(xiàn)方法與操作注意事項,需要的朋友可以參考下
    2020-02-02
  • 使用Vant如何完成各種Toast提示框

    使用Vant如何完成各種Toast提示框

    這篇文章主要介紹了使用Vant如何完成各種Toast提示框,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-05-05
  • vue3中實現(xiàn)拖拽排序代碼示例(vue-draggable-next的使用)

    vue3中實現(xiàn)拖拽排序代碼示例(vue-draggable-next的使用)

    在Vue3中使用拖拽功能時應選用vue-draggable-next插件,傳統(tǒng)的draggable插件不兼容Vue3,可能導致TypeError錯誤,安裝后,需在項目中引入并使用,具體步驟包括安裝插件、引入使用、查看效果和相關說明,需要的朋友可以參考下
    2024-09-09
  • vue.js內(nèi)部自定義指令與全局自定義指令的實現(xiàn)詳解(利用directive)

    vue.js內(nèi)部自定義指令與全局自定義指令的實現(xiàn)詳解(利用directive)

    這篇文章主要給大家介紹了關于vue.js內(nèi)部自定義指令與全局自定義指令的實現(xiàn)方法,vue.js中實現(xiàn)自定義指令的主要是利用directive,directive這個單詞是我們寫自定義指令的關鍵字,需要的朋友們下面跟著小編來一起學習學習吧。
    2017-07-07
  • 由淺入深講解vue2和vue3的區(qū)別

    由淺入深講解vue2和vue3的區(qū)別

    最近發(fā)現(xiàn)很多要求Vue3的技術了,不得不說it技術的更新真的太快了,作為vue2老用戶,我們在學習Vue3前應該了解他們的區(qū)別以及背后的原因,下面這篇文章主要給大家介紹了關于vue2和vue3區(qū)別的相關資料,需要的朋友可以參考下
    2023-02-02
  • 如何在vue中使用百度地圖添加自定義覆蓋物(水波紋)

    如何在vue中使用百度地圖添加自定義覆蓋物(水波紋)

    這篇文章主要給大家介紹了關于如何在vue中使用百度地圖添加自定義覆蓋物(水波紋)的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-11-11
  • vue Tooltip提示動態(tài)換行問題

    vue Tooltip提示動態(tài)換行問題

    這篇文章主要介紹了vue Tooltip提示動態(tài)換行問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • 使用vue-antd動態(tài)切換主題

    使用vue-antd動態(tài)切換主題

    這篇文章主要介紹了使用vue-antd動態(tài)切換主題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • vue中解決el-date-picker更改樣式不生效問題

    vue中解決el-date-picker更改樣式不生效問題

    在使用Vue.js進行前端開發(fā)的過程中,Element?UI?是一個非常流行的UI庫,它提供了一套完整的組件來快速搭建美觀的用戶界面,但是我們經(jīng)常遇到一個問題使用Element?UI提供的el-date-picker組件時,嘗試自定義其樣式卻無法生效,所以本文給大家介紹如何解決這個問題
    2024-10-10

最新評論