上篇文章介紹了Vue構造函數的部分實現,當前Vue實例不是組件時,會執行mergeOptions方法。vue
vm.$options = mergeOptions( resolveConstructorOptions(vm.constructor), options || {}, vm )
mergeOptions方法,咱們以後的博文再來作詳細介紹。今天主要研究resolveConstructorOptions方法,從字面意思來看,這個方法是來解析constructor上的options屬性的。咱們來看源碼。webpack
export function resolveConstructorOptions (Ctor: Class<Component>) { let options = Ctor.options // 有super屬性,說明Ctor是Vue.extend構建的子類 if (Ctor.super) { const superOptions = resolveConstructorOptions(Ctor.super) const cachedSuperOptions = Ctor.superOptions // Vue構造函數上的options,如directives,filters,.... if (superOptions !== cachedSuperOptions) { // super option changed, // need to resolve new options. Ctor.superOptions = superOptions // check if there are any late-modified/attached options (#4976) const modifiedOptions = resolveModifiedOptions(Ctor) // update base extend options if (modifiedOptions) { extend(Ctor.extendOptions, modifiedOptions) } options = Ctor.options = mergeOptions(superOptions, Ctor.extendOptions) if (options.name) { options.components[options.name] = Ctor } } } return options }
這個方法要分紅兩種狀況來講明,第一種是Ctor是基礎Vue構造器的狀況,另外一種是Ctor是經過Vue.extend方法擴展的狀況。web
當Ctor(Ctor其實就是構造函數)是基礎Vue構造器時,好比是經過new關鍵字新建Vue構造函數的實例npm
const vm = new Vue({ el: '#app', data: { message: 'Hello Chris' } })
這個時候options就是Vue構造函數上的options。以下圖
那麼這個options是在哪裏定義的呢?在以前的代碼中好像沒有看到options的定義在哪裏?此時咱們應該怎麼去找這個options定義的地方呢?
這裏教你們一個方法,首先找到package.json,在這裏能夠找到咱們平時用到的一些npm腳本。以npm run dev爲例。實際上npm run dev是執行了下列的命令"dev": "rollup -w -c scripts/config.js --environment TARGET:web-full-dev"
rollup是相似於webpack的打包工具。咱們能夠看到這條命令指向了一個地址scripts/config,以後還指定了一個Target。找到script/config,發現這個文件裏
有TARGET爲web-full-dev的配置。json
// Runtime+compiler development build (Browser) 'web-full-dev': { entry: resolve('web/entry-runtime-with-compiler.js'), dest: resolve('dist/vue.js'), format: 'umd', env: 'development', alias: { he: './entity-decoder' }, banner }
來分析上面的代碼,入口文件的地址在web/entry-runtime-with-compiler.js。這個文件就是對Vue構造函數進行的第一層包裝了。因爲今天分析的是options相關的內容,而這層包裝裏沒有options相關的內容,因此這個文件咱們不展開講(以後有文章會詳細介紹)。可是注意這裏的代碼segmentfault
... import Vue from './runtime/index' ...
咱們Vue構造函數的第二層包裝,就在這個文件裏了。忽略其餘的代碼,咱們來看關於Vue.options的部分api
... import Vue from 'core/index' // 第三層包裝 import platformDirectives from './directives/index' import platformComponents from './components/index' ... // install platform runtime directives & components extend(Vue.options.directives, platformDirectives) extend(Vue.options.components, platformComponents) ... // platformDirectives相關 // 這裏導出Vue全局指令model,show import model from './model' import show from './show' export default { model, show } // platformComponents相關 // 這裏導出Vue全局組件Transition,TransitionGroup import Transition from './transition' import TransitionGroup from './transition-group' export default { Transition, TransitionGroup }
上面的代碼主要是給Vue.options.directives添加model,show屬性,給Vue.options.components添加Transition,TransitionGroup屬性。那麼還有filters,_base屬性,以及components中的KeepAlive又是怎麼來的呢?
這就要看Vue的第三層包裝裏都作了些什麼?找到core/index,一樣咱們只看Vue.options相關代碼。app
mport Vue from './instance/index' import { initGlobalAPI } from './global-api/index' ... initGlobalAPI(Vue) ...
instance/index 就是咱們第二篇文章——構造函數定義的那個文件。這個文件咱們以前看過,沒有和Vue構造函數options相關的代碼。那麼咱們剩下的沒有配置的options必定是在initGlobalAPI上配置了。接來下看看/global-api/index的代碼。函數
/* @flow */ import { ASSET_TYPES } from 'shared/constants' ... export function initGlobalAPI (Vue: GlobalAPI) { ... 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) ... } // shared/constants.js export const ASSET_TYPES = [ 'component', 'directive', 'filter' ] // core/components/index import KeepAlive from './keep-alive' export default { KeepAlive }
上面這層包裝就把filters,_base和components中的KeepAlive都實現了。經過這三層包裝,Vue構造函數的options對象就生成了,看這些文字可能有點繞,咱們直接上圖。工具
回到resolveConstructorOptions的源碼中,當Ctor.super不存在時,直接返回基礎構造器的options。即上圖通過兩次包裝的options。那麼Ctor.super是什麼呢?
Ctor.super是經過Vue.extend構造子類的時候。Vue.extend方法會爲Ctor添加一個super屬性,指向其父類構造器
Vue.extend = function (extendOptions: Object): Function { ... Sub['super'] = Super ... }
因此當Ctor時基礎構造器的時候,resolveConstructorOptions方法返回基礎構造器的options。除了Ctor是基礎構造器以外,還有一種是Ctor是經過Vue.extend構造的子類。這種狀況比較複雜,下一篇文章專門對其進行介紹,敬請期待!