国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

vue@2.0源碼學習---組件究竟是什么

PiscesYE / 2744人閱讀

摘要:定義一個組件如下打印如下再回過頭看,可以發現他做的工作就是擴展一個構造函數,并將這個構造函數添加到現在我們已經可以回答最開始的問題的組件是什么的組件其實就是擴展的構造函數,并且在適當的時候實例化為實例。

vue@2.0源碼學習---組件究竟是什么

本篇文章從最簡單的情況入手,不考慮prop和組件間通信。

Vue.component

vue文檔告訴我們可以使用Vue.component(tagName, options)注冊一個組件

Vue.component("my-component", {
  // 選項
})

毫無疑問這是一個全局API,我們順著代碼最終可以找到Vue.component是這樣的

Vue.component = function(id, definition) {
    definition.name = definition.name || id
    definition = Vue.extend(definition)
    this.options[type + "s"][id] = definition
    return definition    
}

Vue.component實際上是Vue.extend的封裝,Vue.extend如下:

Vue.extend = function (extendOptions: Object): Function {
  extendOptions = extendOptions || {}
  const Super = this
  const isFirstExtend = Super.cid === 0
  if (isFirstExtend && extendOptions._Ctor) {
    return extendOptions._Ctor
  }
  let 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
  // allow further extension
  Sub.extend = Super.extend
  // create asset registers, so extended classes
  // can have their private assets too.
  config._assetTypes.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
  // cache constructor
  if (isFirstExtend) {
    extendOptions._Ctor = Sub
  }
  return Sub
}

可以看到Vue.extend返回的實際上是一個構造函數Sub,并且此構造函數繼承自Vue。里面有這么幾行代碼

  Sub.options = mergeOptions(
    Super.options,
    extendOptions
  )

那么Super.options(即Vue.options)是什么呢?

  Vue.options = Object.create(null)
  //  包含components directives filters
  config._assetTypes.forEach(type => {
    Vue.options[type + "s"] = Object.create(null)
  })

  util.extend(Vue.options.components, builtInComponents)

Vue.options事實上存放了系統以及用戶定義的component、directive、filter,builtInComponents為Vue內置的組件(如keep-alive),打印看下:

所以Sub構造函數的options不僅包含components、directives、filters,還包含預先定義的實例化時所需的選項。定義一個組件如下:

let MyComponent = Vue.extend({
    data() {
        return {
            msg: "this"s compoennt"
        }
    },
    render(h) {
        return h("p", this.msg)
    }
})

打印MyComponent.options如下:

再回過頭看Vue.component,可以發現他做的工作就是擴展一個Vue構造函數(VueComponent),并將這個構造函數(VueComponent)添加到Vue.options.components

現在我們已經可以回答最開始的問題---vue的組件是什么?vue的組件其實就是擴展的Vue構造函數,并且在適當的時候實例化為Vue實例。

組件對應的vnode

組件對應的vnode是什么樣子?從一個簡單的例子入手:

let MyComponent = Vue.component("my-component", {
    data() {
        return {
            msg: "this"s component"
        }
    },
    render(h) {
        return h("p", this.msg)
    }
})

window.app = new Vue({
    render(h) {
        return h("my-component")
    }
}).$mount("#root")

上篇文章已經說道在initRender的時候會初始一個系統watcher,如下:

vm._watcher = new Watcher(vm, () => {
  vm._update(vm._render(), hydrating)
}, noop)

上篇文章提到vm._render()返回的是一個虛擬dom(vnode),具體到本篇,那么組件標簽會被解析成什么樣的虛擬節點呢?

事實上render的時候會首先調用createElement,根據傳入的tag(html標簽或者組件標簽)不同,vnode可以分為以下兩種:

platform built-in elements

這種就是普通的html標簽(p、div、span等)對應的vnode

component

當tag是組件標簽的時候,會調用createComponent,如下:

    else if ((Ctor = resolveAsset(context.$options, "components", tag))) {
      // component
      
      return createComponent(Ctor, data, context, children, tag)
    }

這里的Ctor就是我們擴展的組件構造函數,createComponent最終返回的vnode如下:

  const vnode = new VNode(
    `vue-component-${Ctor.cid}${name ? `-${name}` : ""}`,
    data, undefined, undefined, undefined, undefined, context,
    { Ctor, propsData, listeners, tag, children }
  )

需要注意的是data有一個操作:

  // merge component management hooks onto the placeholder node
  mergeHooks(data)

merge之后data.hook會添加四個方法:

init 實例化組件時調用

prepatch patch之前調用

insert 真實節點插入時調用

destory 組件實例銷毀時調用

實例化組件

前文看到組件構造函數實際上是存在組件對應vnode的componentOptions中,那么究竟是什么時候實例化組件呢?

順著vm._update(vm._render(), hydrating)往下看發現最終調用的是patch操作,而對于組件實例化而言并不存在與之對應的oldVnode(因為oldVnode是在組件更新后產生的),所以最終的邏輯歸到根據組件對應的vnode創建真實dom節點,即

createElm(vnode, insertedVnodeQueue)

我們還記得組件的構造函數是vnode.componentOptions.Ctor,其實最終調用的也是這個構造函數。

createElm函數中與組件初始化相關的關鍵代碼如下:

    const data = vnode.data
    if (isDef(data)) {
      if (isDef(i = data.hook) && isDef(i = i.init)) i(vnode)

      if (isDef(i = vnode.child)) {
        initComponent(vnode, insertedVnodeQueue)
        return vnode.elm
      }
    }

init的代碼如下:

function init (vnode: VNodeWithData, hydrating: boolean) {
  if (!vnode.child || vnode.child._isDestroyed) {
    const child = vnode.child = createComponentInstanceForVnode(vnode, activeInstance)
    child.$mount(hydrating ? vnode.elm : undefined, hydrating)
  }
}


export function createComponentInstanceForVnode (
  vnode: any, // we know it"s MountedComponentVNode but flow doesn"t
  parent: any // activeInstance in lifecycle state
): Component {
  const vnodeComponentOptions = vnode.componentOptions
  const options: InternalComponentOptions = {
    _isComponent: true,
    parent,
    propsData: vnodeComponentOptions.propsData,
    _componentTag: vnodeComponentOptions.tag,
    _parentVnode: vnode,
    _parentListeners: vnodeComponentOptions.listeners,
    _renderChildren: vnodeComponentOptions.children
  }
  // check inline-template render functions
  const inlineTemplate = vnode.data.inlineTemplate
  if (inlineTemplate) {
    options.render = inlineTemplate.render
    options.staticRenderFns = inlineTemplate.staticRenderFns
  }

  return new vnodeComponentOptions.Ctor(options)
}

經過init之后可以看到組件vnode.child對應的就是組件的實例,且child.$el即為組件對應的真實dom,但是實際上createElm返回的是vnode.elm,怎么回事?事實上initComponent
中做了處理

vnode.elm = vnode.child.$el

綜上,組件實例化是在由虛擬dom映射為真實dom時完成的。

寫到這里已經對組件機制有了初步的認識,數據的傳遞、父子組件通信本文并沒有涉及,留到以后再看。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/90375.html

相關文章

  • 前端資源系列(4)-前端學習資源分享&前端面試資源匯總

    摘要:特意對前端學習資源做一個匯總,方便自己學習查閱參考,和好友們共同進步。 特意對前端學習資源做一個匯總,方便自己學習查閱參考,和好友們共同進步。 本以為自己收藏的站點多,可以很快搞定,沒想到一入匯總深似海。還有很多不足&遺漏的地方,歡迎補充。有錯誤的地方,還請斧正... 托管: welcome to git,歡迎交流,感謝star 有好友反應和斧正,會及時更新,平時業務工作時也會不定期更...

    princekin 評論0 收藏0
  • 有價值的前端技術點

    摘要:借著產品層面的功能和視覺升級,我們用對它進行了一次技術重構。前端優化是一個讓人技術提升的,希望你也能從這里學到一些東西。年最流行的前端鏈接我們每周會給多名前端開發者發送新聞郵件。 面試 -- 網絡 HTTP 現在面試門檻越來越高,很多開發者對于網絡知識這塊了解的不是很多,遇到這些面試題會手足無措。本篇文章知識主要集中在 HTTP 這塊。文中知識來自 《圖解 HTTP》與維基百科,若有錯...

    microelec 評論0 收藏0
  • Vue原理】Component - 白話版

    摘要:寫文章不容易,點個贊唄兄弟專注源碼分享,文章分為白話版和源碼版,白話版助于理解工作原理,源碼版助于了解內部詳情,讓我們一起學習吧研究基于版本如果你覺得排版難看,請點擊下面鏈接或者拉到下面關注公眾號也可以吧原理白話版從模板上使用到掛載到頁面 寫文章不容易,點個贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內部詳情,讓我們一起學習吧研究基于...

    liuyix 評論0 收藏0
  • Vue 2.0 升(cai)級(keng)之旅

    摘要:前言這節凈是些嘮叨,只想看升級的可直接跳過。在不久之前,如約發布了版本。正如計劃之初,博客的版本也將升級到。升級之旅首先,升級依賴。那該怎么做哪再一次谷哥和查閱文檔,然而一無所獲。返回的是整個項目路由的實例,它是只讀的。 Troubleshooting of upgrading Vue from 1.0 to 2.0 系列文章: Vue 2.0 升(cai)級(keng)之旅 (本...

    lidashuang 評論0 收藏0
  • 前端經典文章

    摘要:上周末看這篇文章時,偶有靈光,所以,分享出來給大家一起看看前端面試四月二十家前端面試題分享請各位讀者添加一下作者的微信公眾號,以后有新的文章,將在微信公眾號直接推送給各位,非常感謝。 前端切圖神器 avocode 有了這個神器,切圖再也腰不酸,腿不疼了。 這一次,徹底弄懂 JavaScript 執行機制 本文的目的就是要保證你徹底弄懂javascript的執行機制,如果讀完本文還不懂,...

    lowett 評論0 收藏0

發表評論

0條評論

PiscesYE

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<