上篇文章介绍了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构造的子类。这种状况比较复杂,下一篇文章专门对其进行介绍,敬请期待!