从 vue 源码看问题 — 你真的了解 Vue 全局 Api 吗?

前言

在使用 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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值