在Vue 2中需要向响应式对象添加新属性时,可以使用Vue.set$set方法来实现。这两个方法的作用是向响应式对象添加属性并确保这个新属性也是响应式的。

 为什么会有vue.set方法

Vue提供了Vue.set方法主要是为了解决在Vue 2.x 中动态添加属性时可能遇到的响应性问题。

在Vue中,当一个对象被创建时,Vue会将其属性转换为响应式属性,以便能够在属性发生变化时触发视图更新。然而,如果在已经创建的对象上直接添加新属性,新属性默认不会具有响应性,因为Vue无法在对象被创建时对新属性进行响应式处理。

为了解决这个问题,Vue提供了Vue.set方法。通过Vue.set方法,Vue能够动态地向已有的响应式对象添加新属性,并确保这个新属性也是响应式的,从而能够在新属性发生变化时触发视图更新。

vue.set方法怎么实现的

vue.set方法首先会区分是对数组还是对象进行新增属性:

数组新增元素

如果是数组:利用vue2改写后的splice方法进行元素插入(此时$set是向数组里新增一个元素)。

对象新增key和value

如果是对象分情况讨论

    对象本身就有这个key,替换传进来的value即可,不用考虑对象是否为响应式
    对象本身没有这个key。考虑对象是否为响应式对象。如果是响应式对象,调用defineReactive给当前对象的key增加响应式依赖。否则,对象不是响应式的,直接给对象加属性,不用考虑响应式问题。

思考:如何知道对象是不是响应式的对象?

在Vue中,每个响应式对象都会有一个__ob__属性,该属性是一个Observer对象,用于跟踪对象的变化。通过检查对象是否具有__ob__属性,可以判断一个对象是否是响应式的。

Vue.set / $set 伪代码实现

在Vue 2中,Vue.set$set方法的实现原理主要涉及到响应式系统中的依赖收集和触发更新机制。下面是这两个方法源码的简单实现:

首先,入参是目标对象obj,新增的属性key值,新增的属性value值

其次:按照流程先判断是否为数组,用Array.isArray等判断,对数组的新增用splice方法

用key in obj判断key是否是obj中已有的属性,如果是,直接修改value值。

判断是否为响应式对象,利用响应式对象本身被加了__ob__属性区分。如果不是响应式这届修改。

继续,如果以上都不成立,那么就是给响应式对象obj添加一个响应式属性key,调用defineReactive方法给对象的指定key加响应式。

// Vue.set 方法定义
Vue.set = function (obj, key, value) {
 //判断是否为数组
  if (Array.isArray(obj) && isValidArrayIndex(key)) {
    obj.length = Math.max(obj.length, key);
    obj.splice(key, 1, value);//数组新增元素调用splice
    return value;
  }
 //判断对象本身是否有这个key
  if (key in obj && !(key in Object.prototype)) {
    obj[key] = value;
    return value;
  }
//vue在响应式拦截的时候会为定义响应式的对象加上__ob__属性,可以用它区分对象是否为响应式对象
  const ob = obj.__ob__;
//非响应式对象
  if (!ob) {
    obj[key] = value;
    return value;
  }
//响应式对象,给这个key加响应式
  defineReactive(ob.value, key, value);
  ob.dep.notify();
  return value;
};

// $set 方法定义
Vue.prototype.$set = function (target, key, value) {
  return Vue.set(target, key, value);
};

源码

GitHub 加速计划 / vu / vue
207.54 K
33.66 K
下载
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
最近提交(Master分支:2 个月前 )
73486cb5 * chore: fix link broken Signed-off-by: snoppy <michaleli@foxmail.com> * Update packages/template-compiler/README.md [skip ci] --------- Signed-off-by: snoppy <michaleli@foxmail.com> Co-authored-by: Eduardo San Martin Morote <posva@users.noreply.github.com> 4 个月前
e428d891 Updated Browser Compatibility reference. The previous currently returns HTTP 404. 5 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐