Vue 无法检测到对象属性的添加或删除。由于 Vue 会在初始化实例时对属性执行 getter/setter 转化,所以属性必须在 data 对象上存在才能让 Vue 将它转换为响应式的。但是 Vue 提供了 Vue.set (object, propertyName, value) / vm.$set (object, propertyName, value) 来实现为对象添加响应式属性,那框架本身是如何实现的呢?
Vue 源码
export function set (target: Array | Object, key: any, val: any): any {
// target 为数组
// 判断目标值是否为数组,并且key值是否为有效的数组索引
if (Array.isArray(target) && isValidArrayIndex(key)) {
// 修改数组的长度, 避免索引>数组长度导致splcie()执行有误
// 对比数组的key值和数组长度,取较大值设置为数组的长度
target.length = Math.max(target.length, key)
// 利用数组的splice变异方法触发响应式
target.splice(key, 1, val)
return val
}
// key 已经存在,直接修改属性值
// 如果目标值是对象,并且key值是目标值存在的有效key值,并且不是原型上的key值
if (key in target && !(key in Object.prototype)) {
// 直接更改目标值
target[key] = val
return val
}
const ob = (target: any).__ob__
// target 本身就不是响应式数据, 直接赋值
if (!ob) { // 如果目标值不是响应式的,那么值需要给对应的key赋值
target[key] = val
return val
}
// 对属性进行响应式处理
defineReactive(ob.value, key, val)
ob.dep.notify()
return val
}
【vue|快速理解Vue 使用 vm.$set 解决对象新增属性不能响应的问题】阅读以上源码可知,vm.$set 的实现原理是:
如果目标是数组,直接使用数组的 splice 方法触发相应式;
如果目标是对象,会先判读属性是否存在、对象是否是响应式,最终如果要对属性进行响应式处理,则是通过调用 defineReactive 方法进行响应式处理( defineReactive 方法就是 Vue 在初始化对象时,给对象属性采用 Object.defineProperty 动态添加 getter 和 setter 的功能所调用的方法)
推荐阅读
- Vue|ssm和vue实现图片的上传和回显,以及图片的访问
- 每周知识总结|每周知识总结(五)
- vue|vue5 if与show
- vue搜索过滤
- vue|vue3 class样式
- vue|vue导航栏自定义设置带图片(选中状态刷新不消失)
- 两个数组拿相同元素,数组去重,两个日期区间段合并
- elementUI编辑时清除表单检验
- javascript|基于jquery扩展漂亮的单选按钮——RadioButton