前言
在使用 Vue 框架在进行开发时,不免会使用到一些 global-api 或者是实例上的 api(本质上也是调用了全局 api ,相当于是别名),用于解决在项目遇到的一些问题,比如:this.$set()、this.$nextTick()
等等。还有一些全局 api 很可能只是因为不了解这个 api 的作用,所以一直没有找到合适的场景去使用它,那现在我们就通过源码层面看看这些全局 api 的作用是什么,以及了解其对应的原理。
下面是【官方文档目录】和【源码目录】的对比:
深入源码
initGlobalAPI() 方法
文件位置:src\core\global-api\index.js
初始化全局 api,比如:Vue.util = {...}、Vue.options = {...}、Vue.[set | del | nextTick | observable | use | mixin | extend | component | directive | filter]
,详细内容请看下面代码的注释.
// 初始化全局 api 的入口
export function initGlobalAPI (Vue: GlobalAPI) {
// Vue 全局默认配置 config
const configDef = {
}
configDef.get = () => config
// 不允许通过 Vue.config = {} 的方式进行覆盖
if (process.env.NODE_ENV !== 'production') {
configDef.set = () => {
warn(
'Do not replace the Vue.config object, set individual fields instead.'
)
}
}
// 将配置项 config 代理到 Vue 上,支持通过 Vue.config 的方式去访问
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 (to: Object, _from: ?Object), 将 _from 对象上的属性复制到 to 对象
extend,
// 合并配置项
mergeOptions,
// 设置 getter 和 setter,分别进行 依赖收集 和 依赖更新通知
defineReactive
}
// 全局 set 方法,处理数组元素或对象属性的新增或修改
Vue.set = set
// 全局 delete 方法,删除数组元素或对象属性
Vue.delete = del
// 全局 nextTick 方法,主要依赖于浏览的异步任务队列
Vue.nextTick = nextTick
// 2.6 explicit observable API
// 全局 observable 方法,本质就是 observe 方法,将接收对象转换为响应式对象
Vue.observable = <>(obj: T): T => {
observe(obj)
return obj
}
{
/* 为全局 options 设置指定的配置项 Vue.options = { components:{}, directive: {}, filters:{} } */}
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 赋值给 Vue.options._base,向外进行暴露 */}
Vue.options._base = Vue
{
/*
builtInComponents 实际上就是 KeepAlive 组件
将 KeepAlive 注册到 components 全局组件配置当中,即可以直接在全局使用 <keep-alive></keep-alive>
*/}
extend(Vue.options.components, builtInComponents)
{
/* 初始化 Vue.use 方法 */}
initUse(Vue)
{
/* 初始化 Vue.mixin 方法 */}
initMixin(Vue)
{
/* 初始化 Vue.extend 方法 */}
initExtend(Vue)
{
/* 初始化 Vue.component、Vue.directive、Vue.filter 方法 */}
initAssetRegisters(Vue)
}
Vue.set() 方法
文件位置:src\core\observer\index.js
实例上的 vm.$set
是全局 Vue.set
的 别名,目的是向响应式对象中添加一个 property,并确保这个新 property 同样是响应式的,如果 key
已存在就将新值替换旧值,且触发视图更新.
export function set (target: Array<any> | Object, key: any, val: any): any {
if (process.env.NODE_ENV !== 'production' &&
(isUndef(target) || isPrimitive(target))
) {
warn(`Cannot set reactive property on undefined, null, or primitive value: ${
(target: any)}`)
}
// 处理数组:Vue.set(arr, index, value),实现响应式
if (Array.isArray(target) && isValidArrayIndex(key)) {
target.length = Math.max(target.length, key)
// 本质上是通过重写后的 splice 方法进行实现元素替换
target.splice(key, 1, val)
return val
}
/*
处理对象: Vue 无法探测普通的新增 property,如果需要可以通过 Vue.set(this, newKey, value) 进行设置动态的、具有响应式的属性
*/
// 当前对象上存在 key 属性且不属于原型对象上时,直接更新旧值
if (key in target && !(key in Object