vue|如何给data对象添加新的属性☕☕

531 阅读2分钟

1、添加属性

// 平时做项目的时候难免不会对 数组或者对象 进行这样的骚操作操作,结果发现,咦~~,他喵的,怎么页面没有重新渲染。
const vueInstance = new Vue({
 data: {
  arr: [1, 2],
  obj1: {
    a: 3
  }
 }
});
vueInstance.$data.arr[0] = 3; // 这种骚操作页面不会重新渲染
vueInstance.$data.obj1.b = 3; // 这种骚操作页面不会重新渲染

2、界面没有更新

我们发现,obj1.b 已经成功添加,但是视图并未刷新。这是因为在Vue实例创建时,obj1.b并未声明,因此就没有被Vue转换为响应式的属性,自然就不会触发视图的更新,这时就需要使用Vue的全局 api set()

3、使用Vue.set()

Vue.set(vueInstance.$data.arr, 0, 3); // 这样操作数组可以让页面重新渲染
vueInstance.$set(vueInstance.$data.arr, 0, 3); // 这样操作数组也可以让页面重新渲染
Vue.set(vueInstance.$data.obj1, b, 3); // 这样操作对象可以让页面重新渲染
vueInstance.$set(vueInstance.$data.obj1, b, 3); // 这样操作对象也可以让页面重新渲染

4、Vue.set()的解释

Vue.set()和this.$set()实现原理

是时候看一波这两个api的源码了,我们先来看看Vue.set()的源码:

import { set } from '../observer/index'
...
Vue.set = set
...
再来看看this.$set()的源码:
import { set } from '../observer/index'
...
Vue.prototype.$set = set
...

结果我们发现Vue.set()和this.$set()这两个api的实现原理基本一模一样,都是使用了set函数。set函数是从 ../observer/index 文件中导出的,区别在于Vue.set()是将set函数绑定在Vue构造函数上,this.$set()是将set函数绑定在Vue原型上。

5、添加新的属性的几种方法

如果只是添加少量的属性使用Vue.set()

如果是添加很多属性,实现Object.assign(),创建一个新的对象,合并原对象和混入对象的属性

如果实在是不知道怎么办使用forceUpdate强制重新渲染vue实例

6、Vue.set()的原理

用法

向响应式对象中添加一个新的属性,并且保证这个新的属性也是响应式的,触发时,会引起视图的更新。

原理

$set(target,key,val)

(1)判断target是不是null、undefined、原始数据类型,如果是的,返回错误提示;

(2)如果不是,判断是不是数组,如果是的,通过数组的splice方法,更新数组,推荐使用splice方法会比较好自定义,因为splice可以在数组的任何位置进行删除/添加操作

(3)如果不是,说明是对象,那就判断,key是否已经存在,如果存在,就是单纯的更新,

(4)如果不存在,获取target的__ob__属性,判断target是不是vue实例,以及是否是根数据对象,如果是返回错误信息

(5)如果不是,判断target的__ob__属性,如果不存在,说明target不是一个响应式的对象,那直接修改属性即可

(6)如果存在,通过defineReactive方法,将属性添加并转换成响应式的

总结

如果涉及到数组的更新时,就调用splice方法去更新数组 如果是对象新增属性,就通过defineReactive方法,将属性添加到对象转成响应式,并通知更新。

image (18).png

看一个简单版本的

image.png

思考💡:我在学习流程图的时候,看到说判断target的__ob__不存在,就不是响应式对象,__ob__存在就是响应式对象,这是为什么?

源码中,首先定义变量ob的值为 target.__ob__,这个 __ob__属性到底是什么对象呢?原来呀vue给响应式对象都加了一个 __ob__属性,如果一个对象有这个 __ob__ 属性,那么就说明这个对象是响应式对象,我们修改对象已有属性的时候就会触发页面渲染。

参考👀

$set实现原理

vue.$set()原理