一、概述
我们看下Vue源码中文件的依赖顺序
根据es6文件依赖的执行顺序,以上文件的执行顺序是src/core/instance/index.js
、src/core/index.js
、src/platforms/web/runtime/index.js
、src/platforms/web/entry-runtime-with-compiler.js
上篇重读Vue源码系列五—— 逐步揭开Vue构造函数实现原型属性的面纱Vue原型属性初始化的实现是在src/platforms/web/runtime/index.js
中,根据执行顺序这篇将会讲src/core/index.js
先看下源码
import Vue from './instance/index'
import { initGlobalAPI } from './global-api/index'
import { isServerRendering } from 'core/util/env'
import { FunctionalRenderContext } from 'core/vdom/create-functional-component'
initGlobalAPI(Vue) //会给 Vue 这个对象本身扩展全局的静态方法
Object.defineProperty(Vue.prototype, '$isServer', {
get: isServerRendering
})
Object.defineProperty(Vue.prototype, '$ssrContext', {
get () {
/* istanbul ignore next */
return this.$vnode && this.$vnode.ssrContext
}
})
// expose FunctionalRenderContext for ssr runtime helper installation
Object.defineProperty(Vue, 'FunctionalRenderContext', {
value: FunctionalRenderContext
})
Vue.version = '__VERSION__'
export default Vue
我们看到了initGlobalAPI(Vue)
,其实这行代码就是给 Vue 这个对象本身扩展全局的静态方法或者叫全局API。
二、initGlobalAPI
我们看下initGlobalAPI的位置import { initGlobalAPI } from './global-api/index'
global-api
目录就是关于全局API的代码,其实Vue的源码也是按照功能来归类代码的。
export function initGlobalAPI (Vue: GlobalAPI) {
// config
const configDef = {}
configDef.get = () => config
if (process.env.NODE_ENV !== 'production') {
configDef.set = () => {
warn(
'Do not replace the Vue.config object, set individual fields instead.'
)
}
}
Object.defineProperty(Vue, 'config', configDef)
// exposed util methods.
// NOTE: these are not considered part of the public API - avoid relying on
// them unless you are aware of the risk.
Vue.util = {
warn,
extend,
mergeOptions,
defineReactive
}
Vue.set = set
Vue.delete = del
Vue.nextTick = nextTick
// 2.6 explicit observable API
// Vue.observable = <T>(obj: T): T => {
// observe(obj)
// return obj
// }
Vue.observable = obj => {
observe(obj)
return obj
}
Vue.options = Object.create(null)
ASSET_TYPES.forEach(type => {
Vue.options[type + 's'] = Object.create(null)
})
// this is used to identify the "base" constructor to extend all plain-object
// components with in Weex's multi-instance scenarios.
Vue.options._base = Vue
extend(Vue.options.components, builtInComponents)
initUse(Vue)
initMixin(Vue)
initExtend(Vue)
initAssetRegisters(Vue)
}
通过上面的源码我们看到initGlobalAPI
中实现了以下全局API:
- Vue.util
扩展的util方法,这些方法并不会暴露到全局API
Vue.util = {
warn,
extend,
mergeOptions,
defineReactive
}
-
Vue.set 会在Vue实例化之后讲解
-
Vue.delete 会在Vue实例化之后讲解
-
Vue.nextTick 会在Vue实例化之后讲解
-
Vue.observable 会在Vue实例化之后讲解
-
选项/资源Vue.components、Vue.directives、Vue.filters 参考
const ASSET_TYPES = [
'component',
'directive',
'filter'
]
Vue.options = Object.create(null) //创建一个干净的空对象
ASSET_TYPES.forEach(type => {
Vue.options[type + 's'] = Object.create(null)
})
- Vue.options._base = Vue
用于在Weex在中判别Vue对象
-
内置组件keep-alive
extend(Vue.options.components, builtInComponents)
后面讲组件的时候会详细讲解 -
Vue.use
initUse(Vue)
实现Vue.use,主要功能是封装自定义的原型属性比如Vue.prototype.$Toas或者全局注册组件Vue.component的功能,方便使用者,比如我们用element-ui的时候Vue.use(ElementUI); 具体的看参考Vue.use详解
//源码
export function initUse (Vue: GlobalAPI) {
Vue.use = function (plugin: Function | Object) { //Vue.use实现,支持函数或者对象
const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))//防止重复注册
if (installedPlugins.indexOf(plugin) > -1) { //如果已经注册,返回
return this
}
// additional parameters
const args = toArray(arguments, 1)
args.unshift(this) //this其实就是Vue
if (typeof plugin.install === 'function') { //函数的情景
plugin.install.apply(plugin, args)
} else if (typeof plugin === 'function') {
plugin.apply(null, args)
}
installedPlugins.push(plugin)
return this
}
}
- Vue.minx
initMixin(Vue)
,内部用到了_init
里面的mergeOptions,后面会写一篇Vue.minx的实现讲解,现在只要知道就行
export function initMixin (Vue: GlobalAPI) {
Vue.mixin = function (mixin: Object) {
this.options = mergeOptions(this.options, mixin) //this = Vue
return this
}
}
- Vue.extend 使用基础 Vue 构造器,创建一个“子类”。参数是一个包含组件选项的对象。
export function initExtend (Vue: GlobalAPI) {
Vue.cid = 0
let cid = 1
/**
* Class inheritance
* 使用基础 Vue 构造器,创建一个“子类”。参数是一个包含组件选项的对象。
*/
Vue.extend = function (extendOptions: Object): Function {
//代码省略了,详细的会在组件部分讲解
}
}
initAssetRegisters(Vue)
为Vue添加了ASSET_TYPES:component、directive、filter静态方法,定义全局组件、指令、过滤器, 源码如下
const ASSET_TYPES = [
'component',
'directive',
'filter'
]
function initAssetRegisters (Vue: GlobalAPI) {
/**
* Create asset registration methods.
* 组件 指令 过滤器
*/
ASSET_TYPES.forEach(type => {
Vue[type] = function (
id: string,
definition: Function | Object
): Function | Object | void {
if (!definition) {
return this.options[type + 's'][id]
} else {
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && type === 'component') {
validateComponentName(id)
}
if (type === 'component' && isPlainObject(definition)) {
definition.name = definition.name || id
definition = this.options._base.extend(definition)
}
if (type === 'directive' && typeof definition === 'function') {
definition = { bind: definition, update: definition }
}
this.options[type + 's'][id] = definition
return definition
}
}
})
}
三、总结
通过本篇文章和上一篇重读Vue源码系列五—— 逐步揭开Vue构造函数实现原型属性的面纱的讲解,我们大概知道了Vue的全局API和原型属性实现的基本轮廓,现在只需要在大脑中有基本印象就行了。后面讲完实例化部分之后,会写几篇文章分别讲一下主要的API实现逻辑。
现在应该可以看懂下面的图了