Vue2中这些全局Api很重要,谈到源码大家都关注响应原理、模板编译、更新策略这些点,但是Vue在第一步做的事情是注册全局Api,没有全局Api就没有后面的一切
全局Api都在initGlobalAPI函数中初始化
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.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)
}
第一步config的全局配置信息
config 对象来自 share/config.js 中,这里也是使用的Object.defineProperty,因为是的config属性不可删除,不可重新定义,不可枚举,但是config对象里面属性可以任意修改
// 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)
这个config对象就是官网列出的字段,都是很有趣的,我们一一看看
config.optionMergeStrategies 自定义属性合并策略
我们调用 Vue.mixin 的时候,参数对象可以包含 props,data,computd,methods,inject,provide,watch,component,directive,filter,created生命周期等等属性,那每个属性应该怎么合并到实例上,这个就是optionMergeStrategies定义好了,因为不同属性合并策略肯定不一样
我们看一个内置的data属性合并方式,执行mergeDataOrFn内部原理是计算父子data函数的返回值,合并成新对象返回的函数
const strats = config.optionMergeStrategies
strats.data = function (
parentVal: any,
childVal: any,
vm?: Component
): ?Function {
if (!vm) {
if (childVal && typeof childVal !== 'function') {
process.env.NODE_ENV !== 'production' && warn(
'The "data" option should be a function ' +
'that returns a per-instance value in component ' +
'definitions.',
vm
)
return parentVal
}
return mergeDataOrFn(parentVal, childVal)
}
return mergeDataOrFn(parentVal, childVal, vm)
}
于是,我们可以扩展optionMergeStrategies对象,添加新属性的合并自定义策略,实现父子对象嵌套识别相关功能,比如官网的例子
Vue.config.optionMergeStrategies._my_option = function (parent, child, vm) {
return child + 1
}
const Profile = Vue.extend({
_my_option: 1
})
// Profile.options._my_option = 2
config.devtools 开启浏览器devtools插件
为什么开发环境能用devtools,而生产环境不能用呢,原因就在这里
devtools: process.env.NODE_ENV !== 'production'
所以之前遇到一个需求,是让生产环境也能打开devtools,一种就是设置true,那开发和生产环境都有了
config.devtools = true
更通用的做法是做油猴插件来无侵入式,油猴核心代码
// 从html中获取Vue根实例
const rootVm = document.getElementById('app').__vue__
// 获取Vue构造函数
const Vue = rootVm.$options._base
// 或者
// Vue版本是2.6.14,取构造函数需要两次取__proto__
// 可以根据自己的Vue版本做调整,一般是只需要取一次
// const Vue = rootVm.__proto__.__proto__.constructor
// 获取全局配置信息
const config = Vue.config
// 设置devtools为true
Vue.config.devtools = true
// 启动devtool插件,这里来自源码 src\platforms\web\entry-runtime-with-compiler.js,第51行抛出事件
window.__VUE_DEVTOOLS_GLOBAL_HOOK__.emit('init', Vue)
config.errorHandler 异常钩子,sentry监控用这个来获取报错的
errorHandler 这个钩子的作用是用来获取报错的,生产环境在用户端各种问题,监控上做的一般是sentry,errorHandler,sourceMap 来定位问题,关于sourceMap问题可以查看# source-map从入门到放弃和sentry检测