中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

注冊vue 組件的方法有哪些

發布時間:2020-11-20 16:19:30 來源:億速云 閱讀:189 作者:Leah 欄目:開發技術

注冊vue 組件的方法有哪些?針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。

一、了解組件注冊的兩種方式

1.1 全局組件的注冊方法

//main.js 
import Vue from 'vue' 
import App from './App' 
import router from './router' 
Vue.config.productionTip = false 

let Hello = { 
  name: 'hello', 
  template: '這是全局組件hello' 
} 
Vue.component('hello', Hello) 
new Vue({ 
  el: '#app', 
  router, 
  components: { App }, 
  template: '' 
})

上面我們就通過Vue.component()注冊了一個全局組件hello,接下來分析源碼實現的時候也是基于這個例子來進行的。

1.2 局部組件的注冊

 <template>
 <div id="app">
  <img src="./assets/logo.png">
  <HelloWorld/>
 </div>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
 name: 'App',
 components:{
  HelloWorld
 }
}
</script>

像這樣就注冊了一個HelloWorld的局部組件。

二、全局組件注冊的源碼

1.Vue初始化的時候,會調用initGlobalAPI()

//【代碼塊1】
//代碼所在文件:src/core/global-api/index.js
export function initGlobalAPI(Vue: GlobalAPI){
  //...省略其他無關代碼
  initAssetRegisters(Vue)
  //這個方法就是用于組件注冊的方法
}

2.在initAssetRegisters()方法中執行組件的定義

//【代碼塊2】
//代碼所在文件:src/core/global-api/assets.js
export function initAssetRegister(Vue){
  ASSET_TYPES.forEach(type=>{
    //ASSET_TYPES包括component、directive、filter
    Vue[type] = function(id, definition){
      //...一些條件判斷
      if(type === 'component' && isPlainObject(definition)){
        definition.name = definition.name || id 
        definition = this.options._base.extend(definition) 
        //將definition轉換為一個繼承于Vue的構造函數
      }
      //...其他類型的處理
      
      this.options[type+'s'][id] = definition //將這個構造函數掛載到Vue.options.components上
      return definition
    }
  })
}

此時,我們可以單步調試一下我們上面的例子,來看一下definition一開始是什么,以及執行掛載后Vue.options變成了什么樣子:

a.definition: 其實傳入的時候就是我們一開始定義的全局組件的具體內容

注冊vue 組件的方法有哪些

b.Vue.options: 可以看到我們定義的全局組件hello已經存在在Vue.options.components上了

注冊vue 組件的方法有哪些

3.實例化組件的時候,代碼會執行到Vue.prototype._init()上面

//【代碼塊3】
//代碼所在文件:src/core/instance/init.js
Vue.prototype._init = function(options){
  //..省略其他無關代碼
  if(options && options._isComponent){ //組件
    initInternalComponent(vm, options)
  }else{ //非組件
    vm.$options = mergeOptions(
      resolveConstructorOptions(vm.constructor),
      options||{},
      vm
    )
  }
}

這里將自己定義的組件的options與Vue.options做了一個合并,并且賦值給了vm.$options,而通過【代碼塊2】我們可以知道全局組件的構造函數已經被放在了Vue.options.components上,所以經過這一步,vm.$options.components上面也有了全局組件的構造函數。所以現在在任意組件都能拿到全局組件,因為任何組件初始化的時候都會執行這個合并。

我們可以通過單步調試上面的例子看一下現在的vm.$options上面有些什么

注冊vue 組件的方法有哪些

4.在創建vnode的過程中,會執行_createElement方法

//【代碼塊4】
//代碼所在文件:src/core/vdom/create-element.js
export function _createElement(context, tag, data, children, normalization){
  if(typeof tag === 'string'){
    //...
    if(config.isReservedTag(tag)){
      //...保留的html標簽
    }else if(isDef(Ctor = resolveAsset(context.$options, 'component', tag))){
      //已經注冊過的全局組件
      vnode = createComponent(Ctor, data, context, children, tag)
    }else{
      //不是內置標簽也不是已經注冊過的組件,就創建一個全新的vnode
      vnode = new VNode(
        tag, data, children,
        undefined, undefined, context
       )
    }
  }
}

上面代碼中有一個比較重要的方法resolveAsset(),用于判斷在context.$options.compononts(即vm.$options.components)上面是否能找到這個組件的構造函數,如果能找到,返回這個構造函數,(具體方法見【代碼塊5】)根據【代碼塊3】我們可以知道如果這個組件是全局注冊的組件,那么我們就可以得到這個構造函數,并進入這個else if判斷,通過createComponent()得到vnode。

5.上面四步已經實現了整個流程,現在補充看一下resolveAsset()

//【代碼塊5】
//代碼所在文件:src/core/utils/options.js
export function resolveAsset(options, type, id, warnMissing){
   //options即上面調用的時候傳入的context.$options, 
   //由【代碼塊3】,vm.$options是由我們自定義的options以及Vue上的options合并而來的
   //type現在是components
    
   const assets = options[type]
   // check local registration variations first
   if (hasOwn(assets, id)) return assets[id]
   const camelizedId = camelize(id)
   if (hasOwn(assets, camelizedId)) return assets[camelizedId]
   const PascalCaseId = capitalize(camelizedId)
   if (hasOwn(assets, PascalCaseId)) return assets[PascalCaseId]
   // fallback to prototype chain
   const res = assets[id] || assets[camelizedId] || assets[PascalCaseId]
   if (process.env.NODE_ENV !== 'production' && warnMissing && !res) {
    warn(
     'Failed to resolve ' + type.slice(0, -1) + ': ' + id,
     options
    )
   }
   return res
 }

先通過 const assets = options[type] 拿到 assets,然后再嘗試拿 assets[id],這里有個順序,先直接使用 id 拿,如果不存在,則把 id 變成駝峰的形式再拿,如果仍然不存在則在駝峰的基礎上把首字母再變成大寫的形式再拿,如果仍然拿不到則報錯。這樣說明了我們在使用 Vue.component(id, definition) 全局注冊組件的時候,id 可以是連字符、駝峰或首字母大寫的形式。

三、局部組件的注冊

1.extend()

組件在執行render()的時候,會執行createComponent函數,在這個函數里面會執行extend()函數生成一個構造函數,也是在這個extend()函數中,執行了一個options的合并

//【代碼塊5】
//代碼所在文件:src/core/global-api/extend.js
Vue.entend = function(extendOptions){
  //...
  Sub.options = mergeOptions(
     Super.options, //Vue的options
     extendOptions //定義組件的那個對象
  )
  //...
}

可以看出這里是將自己傳入的options(即定義組件的那個對象)與Vue.options合并,然后放到Sub.options上,同時,因為Sub.options上面合并了Vue的options,所以組件里面也可以拿到全局注冊的組件。

2.組件初始化

//【代碼塊6(同代碼塊3)】
//代碼所在文件:src/core/instance/init.js
Vue.prototype._init = function(options){
  //..  
  if(options && options._isComponent){
    initInternalComponent(vm, options)
  }else{
    vm.$options = mergeOptions(
      resolveConstructorOptions(vm.constructor),
      options||{},
      vm
    )
  }
}

組件初始化的過程中會進入if判斷語句,執行initInternalComponent()

3.initInternalComponent()

//【代碼塊7】
//代碼所在文件:src/core/instance/init.js
export function initInternalComponent (vm: Component, options: InternalComponentOptions) {
 const opts = vm.$options = Object.create(vm.constructor.options) 
 //vm.constructor即為Sub,在代碼塊5中,我們已經將局部組件放在了Sub.options上
 //所以這里將局部組件的構造函數放在了vm.$options上
 //這樣在執行【代碼塊4】的時候同樣也能通過resolveAsset得到局部注冊組件的構造函數
 const parentVnode = options._parentVnode
 opts.parent = options.parent
 opts._parentVnode = parentVnode

 //將componentOptions里面的別的屬性賦值給opts
 const vnodeComponentOptions = parentVnode.componentOptions
 opts.propsData = vnodeComponentOptions.propsData
 opts._parentListeners = vnodeComponentOptions.listeners
 opts._renderChildren = vnodeComponentOptions.children
 opts._componentTag = vnodeComponentOptions.tag

 if (options.render) {
  opts.render = options.render
  opts.staticRenderFns = options.staticRenderFns
 }
}

四、總結

由于全局注冊的組件是將組件的構造函數擴展到了Vue.options.components上,而組件在初始化的時候都會將自身options與Vue.options合并,擴展到當前組件的vm.$options.components下,所以全局組件能在任意組件被使用。而局部注冊的組件是將組件的構造函數擴展到了當前組件的vm.$options.components下,所以只能在當前組件使用。

關于注冊vue 組件的方法有哪些問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

石城县| 永靖县| 海晏县| 白城市| 会东县| 广昌县| 仙游县| 哈巴河县| 绥江县| 于都县| 丰城市| 昌黎县| 忻城县| 白山市| 钟祥市| 丰台区| 福建省| 阆中市| 横山县| 克拉玛依市| 师宗县| 惠水县| 乐都县| 湟源县| 中西区| 南投市| 彩票| 苗栗市| 时尚| 玉树县| 蒲江县| 乌苏市| 定西市| 岗巴县| 合江县| 绥芬河市| 牙克石市| 饶河县| 黄冈市| 宁武县| 大厂|