Vue进阶(九十八):Vue.set() 和 this.$set()


一、应用场景

有时候我们会看到如下代码:
在这里插入图片描述
在我们使用vue进行开发的过程中,可能会遇到这样一种情况:当创建vue实例后,再次给对象赋值时,发现数据并不会自动更新到视图上去; 当我们去阅读vue文档的时候,会发现有这么一句话:如果在实例创建之后添加新的属性到实例上,它不会触发视图更新。 如下代码,给 student对象新增 age 属性。

data () {
  return {
    student: {
      name: '',
      sex: ''
    }
  }
}
mounted () { // ——钩子函数,实例挂载之后
  this.student.age = 24
}

二、原因分析

ES5 的限制,Vue.js 不能检测到对象属性的添加或删除,即Vue未做到脏数据检查。因为 Vue.js 在初始化实例时将属性转为 getter/setter,所以属性必须在 data 对象上才能让 Vue.js 转换它,才能让它是响应的。

正确写法:this.$set(this.data,”key”,value')

mounted () {
  this.$set(this.student,"age", 24)
}

Vue 不允许动态添加根级响应式属性。

例如:

const app = new Vue({
  data: {
    a: 1
  }
  // render: h => h(Suduko)
}).$mount('#app1')

Vue.set(app.data, 'b', 2)

此时控制台会报错:
在这里插入图片描述
只可以使用 Vue.set(object, propertyName, value) 方法向嵌套对象添加响应式属性,例如

var vm=new Vue({
    el:'#test',
    data:{
        //data中已经存在info根属性
        info:{
            name:'小明';
        }
    }
});
//给info添加一个性别属性
Vue.set(vm.info,'sex','男');

有童鞋可能会问之前使用过Vue.set()this.$set()Vue.set有什么联系呢?

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

源码分析

先来看看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原型上。

再来看下set源码:

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)}`)
  }
  
  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 (target._isVue || (ob && ob.vmCount)) {
    process.env.NODE_ENV !== 'production' && warn(
      'Avoid adding reactive properties to a Vue instance or its root $data ' +
      'at runtime - declare it upfront in the data option.'
    )
    return val
  }
  
  if (!ob) {
    target[key] = val
    return val
  }
  
  defineReactive(ob.value, key, val)
  ob.dep.notify()
  return val
}

我们发现set函数接收三个参数分别为 target、key、val,其中target的值为数组或者对象,这正好和官网给出的调用Vue.set()时传入的参数对应上。
在这里插入图片描述

四、延伸阅读

上文讲解了应用Vue.setthis.$set 实现动态添加对象属性,视图层随之动态渲染。其实,还有另外一种方法可以解决以上问题,那就是通过添加 this.$forceUpdate() 在修改数据后执行即可。有关 this.$forceUpdate() 的讲解,详参博文🔎《跨平台应用开发进阶(五) :uni-app 实现列表项左划操作》。

五、拓展阅读

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

No Silver Bullet

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值