源码阅读路径src/core/global-api/index.js
此文件主要做了以下几件事:
- 定义Vue.config的属性,如下图所示(Vue.config.png)
- Vue.util上定义一些方法,(慎用)
- 定义全局方法 Vue.set、Vue.delete、Vue.nextTick、Vue.observable
- 初始化Vue.options[components | directives | filters]为空
- 增加全局组件(keep-alive、Transition)
- 定义全局方法Vue.use、Vue.mixin、Vue. extend、Vue. component、Vue. filter、Vue. directive
入口文件
import config from '../config'
import { initUse } from './use'
import { initMixin } from './mixin'
import { initExtend } from './extend'
import { initAssetRegisters } from './assets'
import { set, del } from '../observer/index'
import { ASSET_TYPES } from 'shared/constants'
import builtInComponents from '../components/index'
import { observe } from 'core/observer/index'
// 导入内置方法
import {
warn,
extend,
nextTick,
mergeOptions,
defineReactive
} from '../util/index'
export function initGlobalAPI (Vue: GlobalAPI) {
// 定义静态属性
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) // Vue.config
// 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 // 结束此轮循环后执行回调,常用于需要等待DOM更新或加载完成后执行的功能
// 2.6 explicit observable API
// 对一个新对象添加响应
Vue.observable = T => {
observe(obj) // Proxy
return obj
}
Vue.options = Object.create(null)
ASSET_TYPES.forEach(type => {
// Vue.options.components
// Vue.options.directives
// Vue.otpions.filters
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.\
// 在Weex的多实例场景中,它用于标识“基本”构造函数以扩展所有对象组件。
Vue.options._base = Vue
// 扩展全局组件,增加keep-alive、Transition组件
extend(Vue.options.components, builtInComponents)
initUse(Vue) // 初始化Vue.use方法
initMixin(Vue) // 初始化Vue.mixin
initExtend(Vue) // 初始化Vue.extend
initAssetRegisters(Vue) // 初始化Vue.component Vue.filter Vue.directive
}
核心方法Vue.extend
initExtend
// 导入资源类型,模块方法和辅助方法
import { ASSET_TYPES } from 'shared/constants'
import { defineComputed, proxy } from '../instance/state'
import { extend, mergeOptions, validateComponentName } from '../util/index'
// 定义并导出initExtend
export function initExtend (Vue: GlobalAPI) {
// 每个实例构造函数,包括Vue都有唯一的cid。
// 这使我们能够为原型继承创建包装的“子构造函数”并缓存它们。
/**
* Each instance constructor, including Vue, has a unique
* cid. This enables us to create wrapped "child
* constructors" for prototypal inheritance and cache them.
*/
// 设置Vue的cid为0
Vue.cid = 0
// 定义cid变量
let cid = 1
// 定义类继承方法
/**
* Class inheritance
*/
// 定义Vue类静态方法extend,接受扩展选项对象
Vue.extend = function (extendOptions: Object): Function {
// extendOptions若未定义则设置为空对象
extendOptions = extendOptions || {}
// 存储父类和父类的cid
const Super = this
const SuperId = Super.cid
// 定义缓存构造器对象,如果扩展选项的_Ctor属性未定义则赋值空对象
const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})
// 如果缓存构造器已存有该构造器,则直接返回
if (cachedCtors[SuperId]) {
return cachedCtors[SuperId]
}
// 获取扩展配置对象名称或父级配置对象名称属性,赋值给name
const name = extendOptions.name || Super.options.name
// 在非生产环境下验证name是否合法并给出警告
if (process.env.NODE_ENV !== 'production' && name) {
validateComponentName(name)
}
// 定义子类构造函数
const Sub = function VueComponent (options) {
this._init(options)
}
// 实现子类原型继承,原型指向父类原型,构造器指向Sub
Sub.prototype = Object.create(Super.prototype)
Sub.prototype.constructor = Sub
// 定义子类cid,并递增cid
Sub.cid = cid++
// 定义子类options属性,合并配置对象
Sub.options = mergeOptions(
Super.options,
extendOptions
)
// 定义子类super属性,指向父类
Sub['super'] = Super
// 对于props和computed属性,扩展时在Vue实例上定义了代理getter。
// 这避免了对每个创建的实例执行Object.defineProperty调用。
// For props and computed properties, we define the proxy getters on
// the Vue instances at extension time, on the extended prototype. This
// avoids Object.defineProperty calls for each instance created.
// 初始化子类的props
if (Sub.options.props) {
initProps(Sub)
}
// 初始化子类的计算属性
if (Sub.options.computed) {
initComputed(Sub)
}
// 定义子类的全局API,扩展、混入和使用插件
// allow further extension/mixin/plugin usage
Sub.extend = Super.extend
Sub.mixin = Super.mixin
Sub.use = Super.use
// 创建子类的资源注册方法,允许子类有私有资源
// create asset registers, so extended classes
// can have their private assets too.
ASSET_TYPES.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
Sub.sealedOptions = extend({}, Sub.options)
// 缓存子类构造函数
// cache constructor
cachedCtors[SuperId] = Sub
// 返回
return Sub
}
}
// 定义初始化propss函数
function initProps (Comp) {
// 获取配置对象的props属性
const props = Comp.options.props
// 设置代理
for (const key in props) {
proxy(Comp.prototype, `_props`, key)
}
}
// 定义初始化计算属性函数
function initComputed (Comp) {
// 获取配置对象的computed属性
const computed = Comp.options.computed
// 设置代理
for (const key in computed) {
defineComputed(Comp.prototype, key, computed[key])
}
}
extend 方法是最为复杂的全局API了,它在扩展类实现继承时进行了很多处理:除去判断是否有已存储的子类构造函数之外,首先是实现类继承,原理是原型式继承;然后为子类初始化props和computed属性的代理:最后是扩展全局API。另外对继承的父类的属性也进行了引用存储。
initUse
// 导入toArray辅助函数
import { toArray } from '../util/index'
// 定义并导出initUse函数
export function initUse (Vue: GlobalAPI) {
// 定义Vue类静态方法use,接受插件函数或对象
Vue.use = function (plugin: Function | Object) {
// 定义内部属性installedPlugins,存放已安装插件
// 首次应用时定义为空数组
const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))
// 检测是否安装过传入的插件,已存在则返回
if (installedPlugins.indexOf(plugin) > -1) {
return this
}
// 处理附加参数,加入参数Vue
// additional parameters
// 将传入的参数转化为数组
const args = toArray(arguments, 1)
// 插入Vue类本身为第一个元素
args.unshift(this)
// 如果插件有install方法,则在plugin对象上调用并传入新参数
if (typeof plugin.install === 'function') {
plugin.install.apply(plugin, args)
} else if (typeof plugin === 'function') {
// 如果plugin本身是函数,则直接调用并传入新参数
plugin.apply(null, args)
}
// 向缓存插件数组中添加此插件并返回
installedPlugins.push(plugin)
return this
}
}
initMixin
// 导入mergeOptions辅助函数
import { mergeOptions } from '../util/index'
// 定义并导出initMixin函数
export function initMixin (Vue: GlobalAPI) {
// 定义Vue的静态方法mixin
Vue.mixin = function (mixin: Object) {
// 合并配置对象,重置Vue类的静态属性options
this.options = mergeOptions(this.options, mixin)
// 返回
return this
}
}
initAssetRegisters
// 导入资源类型和辅助函数
import { ASSET_TYPES } from 'shared/constants'
import { isPlainObject, validateComponentName } from '../util/index'
// 定义并注册initAssetRegisters函数
export function initAssetRegisters (Vue: GlobalAPI) {
// 创建资源注册方法
/**
* Create asset registration methods.
*/
// 遍历ASSET_TYPES数组,为Vue定义相应方法
// ASSET_TYPES包括了directive、 component、filter
ASSET_TYPES.forEach(type => {
// 定义资源注册方法,参数是标识名称id,和定义函数或对象
Vue[type] = function (
id: string,
definition: Function | Object
): Function | Object | void {
// 如果未传入definition,则视为获取该资源并返回
if (!definition) {
return this.options[type + 's'][id]
} else {
// 否则视为注册资源
// 非生产环境下给出检验组件名称的错误警告
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && type === 'component') {
validateComponentName(id)
}
// 如果是注册component,并且definition是对象类型
if (type === 'component' && isPlainObject(definition)) {
// 设置definition.name属性
definition.name = definition.name || id
// 调用Vue.extend扩展定义,并重新赋值
definition = this.options._base.extend(definition)
}
// 如果是注册directive且definition为函数
if (type === 'directive' && typeof definition === 'function') {
// 重新定义definition为格式化的对象
definition = { bind: definition, update: definition }
}
// 存储资源并赋值
this.options[type + 's'][id] = definition
// 返回definition
return definition
}
}
})
}