vue中$set用法及其源码的底层原理

vue中$set用法及其源码的底层原理

在我们开发过程中,经常会遇到,为一个数组或者对象data中添加一个属性,点击按钮后发现,控制台打印明明对象中已经出现了这个属性,视图层却并没有更新该数据,这是因为受到JS的限制,vue.js中不能监听对象属性的添加和删除,因为在vue组件初始化过程中,会调用getter和setter方法,所以该属性只有存在data中时,试图层才会响应数据的变化。

当我们对对象属性进行添加和删除的操作时,或者数组通过索引去修改值时都不会触发vue的响应式原理,导致视图并不会渲染,数据也不会并不会改变,这个时候就要使用到$set

解决办法:
(1)通过 s e t 对 象 中 : t h i s . set 对象中:this. setthis.set(obj,key,value)

	student: {
	name:'张三',
	age:16
}
点击事件中:
changeStudent() {
	this.$set(this.student, 'name', '陈皮阿四')
}
console.log(this.student)	//{name:'陈皮阿四',age:16}

数组中:this.$set(obj,index,value)

	student: [1,2,3,'chen']
点击事件中:
changeStudent() {
	this.$set(this.student, 1, 'chenchen')
}
console.log(this.student)	//['chenchen',2,3,'chen']

(2)通过Object.assign(target, sources)方法

student: {
	name:'张三',
	age:16
}
点击事件中:
changeStudent() {
	this.student.name='陈皮阿四'
	this.student = Object.assign({}, this.student)
	console.log(this.student)	// {name:'陈皮阿四',age:16}
}

我们通过这两种方法为对象添加属性之后,他的对象上就多了set和get方法,再次操作属性的时候,就会引起视图的更新了

$set的源码分析
通过传入target,key,value三个值,首先通过isArray判断target是否是数组,是的话则比较key与当前数组
长度的最大值作为数组新长度,然后通过数组splice方法将传入key对应的val值添加进新数组;如果传入的不是
数组则被当做对象处理,通过in方法判断key是否存在target中,如果存在则只是普通的修改值,如果不存在则
说明是对对象属性值的添加或者删除,我们此时要去判断target的__ob__属性,如果为false则说明不是响应式,
只需要简单为他添加上新的属性,如果为true的话则说明是响应式,我们就需要通过defineReactive(将新属
性添加完后转为响应式)将新熟悉添加到target上,最后通知依赖进行更新

 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
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值