问题
今天遇到一个问题:在处理一个list时,要监听list中一个表单值的变化,同时对list其中的项进行回写,如果不判断新旧值相等的问题,就会造成无限循环调用watch回调,所以需要判断oldValue !== newValue
才可以进行对list子项写入的操作。
但是由于监听的是一个表单对象,所以oldValue和newValue永远相等
监听subAuditItemList里Item._formValue 给 Item.extraSubmitParams 赋值
watch(
() => subAuditItemList.map(item => item._formValue),
(newValues, oldValues) => {
newValues.forEach((newValue, index) => {
const item = subAuditItemList[index];
// 检查是否有变化,只有在变化时才更新
console.log(JSON.stringify(item._formValue) !== JSON.stringify(oldValues[index])); // 永远为false
// if (JSON.stringify(item._formValue) !== JSON.stringify(oldValues[index])) {
// root.value.$set(item, 'extraSubmitParams', {
// ...item.extraSubmitParams,
// ...newValue,
// });
// // item.extraSubmitParams = {
// // ...item.extraSubmitParams,
// // ...newValue,
// // };
// }
});
},
{
deep: true
}
);
原理
Vue监听值类型不会出现新旧值打印相等的问题,只有在监听引用类型的时候会遇到新旧相等的问题。
Vue官方的解释是:在变更(不是替换)对象或数组时,新值与旧值相同,因为他们指向同一数组或对象,Vue不会保留变更前值的副本。
解决方案
通过computed对引用类型cloneDeep,watch这个计算属性即可。
原理:深拷贝watch的值内存地址有更新,和watch一个值类型的数据没区别。
const formValueList = computed(() => {
return JSON.parse(JSON.stringify(subAuditItemList.map(item => item._formValue)));
});
watch(
formValueList,
(newValues, oldValues) => {
console.log(JSON.stringify(newValues), JSON.stringify(oldValues));
},
{
deep: true
}
);