我们在日常vue项目开发过程中,有时候我们对数组或者对象进行了一些操作后,发现页面数据没有更新到.
根据官方文档定义:如果在实例创建之后添加新的属性到实例上,它不会触发视图更新。
这是官方的解决方法用的是Vue $sett(object, key, value)
//参数
target:要更改的数据源(可以是对象或者数组)
key:要更改或者新增属性的具体数据 (对象的key为键,数组的key为下标)
value :重新赋的值
首先这是这个方法的源码
待会下面做详细的拆分讲解
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
}
1.首先是讲最上面的一小段
**isUndef
**是判断target是不是等于undefined或者null,isPrimitive
是判断target的数据类型是不是string、number、symbol、boolean中的一种。整个的判断意思是当前环境不是生产环境并且 isUndef(target) || isPrimitive(target) 为真的时候,那么就抛出错误警告
if (process.env.NODE_ENV !== 'production' &&
(isUndef(target) || isPrimitive(target))
) {
warn(`Cannot set reactive property on undefined, null, or primitive value: ${(target: any)}`)
}
2.这里操作数组的更新方法
首先isArray是判断是不是数组,并且key的值是有效的数组索引,然后将target数组的长度设为key中最大的值,这个判断主要是我们查找数组下标的时候,下标值大于数组的长度就会报错,然后使用splice
替换将数组的旧值替换成了新值,从而更新视图。(push、pop、shift、unshift、splice、sort、reverse)七种方法可更新视图
// 数组
if (Array.isArray(target) && isValidArrayIndex(key)) {
target.length = Math.max(target.length, key)
target.splice(key, 1, val)
return val
}
3、这是操作对象的方法,比数组稍微麻烦一些
(1)首先if (key in target && !(key in Object.prototype))
判断这个key是不是当前对象的key 和 这个key 不是object原型的key。说明这个key本来就在对象上面已经定义过了的,直接修改值就可以了,可以自动触发响应。
(2)这时候给对象添加了__obj__
属性,然后又做了判断if (target._isVue || (ob && ob.vmCount))
的意思是:当前的target对象是vue实例对象或者是根数据对象,那么就会抛出错误警告。
(3)这一步才是最核心的地方defineReactive(ob.value, key, val)
这个方法的意思是给新加的属性添加依赖,以后再直接修改这个新的属性的时候就会触发页面渲染。ob.dep.notify()
这个方法可以理解成渲染函数,所以页面就会进行重新渲染
// 对象
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()
总结:Vue $sett(object, key, value) 这个方法确实很好用,不过vue3
出来后这个问题已经不存在了,技术就是这样不断的在更新,只有不断学习才能更好的适应这个市场