Vue的api实现原理

161 阅读2分钟

Vue.$set

先看一下源码(这里忽略了一些增加代码健壮性的逻辑判断)

export function set (target: Array<any> | Object, key: any, val: any): any {
  if (Array.isArray(target) && isValidArrayIndex(key)) {
    target.length = Math.max(target.length, key)
    target.splice(key, 1, val)
    return val
  }
  if (key in target && !(key in Object.prototype)) {
    target[key] = val
    return val
  }
  const ob = (target: any).__ob__
  if (!ob) {
    target[key] = val
    return val
  }
  defineReactive(ob.value, key, val)
  ob.dep.notify()
  return val
}

$set的作用

向响应式对象中添加一个 property,并确保这个新 property 同样是响应式的,且触发视图更新。它必须用于向响应式对象上添加新 property,因为 Vue 无法探测普通的新增 property。
这也就是说你只能给在data中已经定义的对象上新增的属性或者数组中新增内容添加响应式。

参数介绍

$set方法接收3个参数,第一个参数是对象或者数组,第二个参数是对象的键值或数组下标,第三个值是要监听的值。

应用场景

在你事先不知道你需要添加相应式的属性的名称时,可以使用这个api

源码分析

第一个 if 判断是否是传入的第一个参数是否是数组,并且判断传入的key是否是数组的下标。如果满足条件,将key和target.length的值赋值给target.length(如果key大于target.length,那么原有的target的值会变大,例如:target.length为1,length为3时,target数组会变成[xxx,undefined,undefined],修改length也会对原数组产生影响),由于数组的splice操作目标数据(数据的splice已被重写,会在内部自动实现传入值的响应式),最后返回传入值。
第二个if判断key是否存在于参数对象的key中并且key不是对象Object的中的属性。如果满足需求,直接使用新传入的值替换指定属性对应的value,返回传入值。
如果不满足上述两个条件,则说明是对象上新增的属性,获取到目标对象的__ob__(指向监听当前属性的oberserv实例,如果这个值存在,则说明对象已经被监听),给对象上新增一个属性key并赋值,这个过程会自动实现依赖收集。 如果这个对象事先没有在data上定义,直接使用defineReactive给其添加上响应式。并手动刷新页面。