在Vue3中,监听对象数组中某个属性的变化可以通过以下几种方法实现:
方法一:深度监听整个数组并比较属性变化
使用 watch
函数并启用 deep: true
,在回调中遍历比较新旧数组的特定属性。
javascript
复制
下载
import { ref, watch } from 'vue'; const items = ref([ { id: 1, name: 'A' }, { id: 2, name: 'B' } ]); watch( () => [...items.value], // 创建数组副本确保触发响应 (newItems, oldItems) => { newItems.forEach((newItem, index) => { const oldItem = oldItems[index]; if (oldItem && newItem.name !== oldItem.name) { console.log(`Item ${newItem.id}的name变化: ${oldItem.name} => ${newItem.name}`); } }); }, { deep: true } );
优点:简单易用,无需动态管理监听器。
缺点:任何数组或元素属性变化都会触发回调,需手动比较属性,可能影响性能。
方法二:为每个元素单独设置监听器
遍历数组并为每个对象的属性设置独立的 watch
,动态管理监听器的生命周期。
javascript
复制
下载
import { ref, watch, onBeforeUnmount } from 'vue'; const items = ref([ { id: 1, name: 'A' }, { id: 2, name: 'B' } ]); const stops = new Map(); // 使用Map保存监听器的停止函数 // 初始化监听 const setupWatchers = () => { items.value.forEach(item => { if (!stops.has(item.id)) { const stop = watch( () => item.name, (newVal, oldVal) => { console.log(`Item ${item.id}的name变化: ${oldVal} => ${newVal}`); } ); stops.set(item.id, stop); } }); }; // 监听数组变化,动态更新监听器 watch( () => [...items.value], // 触发数组变化 (newItems, oldItems) => { // 移除已删除元素的监听 oldItems.forEach(oldItem => { if (!newItems.some(item => item.id === oldItem.id)) { const stop = stops.get(oldItem.id); if (stop) { stop(); stops.delete(oldItem.id); } } }); // 添加新元素的监听 newItems.forEach(newItem => { if (!stops.has(newItem.id)) { const stop = watch( () => newItem.name, (newVal, oldVal) => { console.log(`Item ${newItem.id}的name变化: ${oldVal} => ${newVal}`); } ); stops.set(newItem.id, stop); } }); }, { deep: true, immediate: true } ); // 组件卸载时清理所有监听 onBeforeUnmount(() => { stops.forEach(stop => stop()); stops.clear(); });
优点:精确监听目标属性,避免不必要的回调。
缺点:需手动管理监听器,逻辑较复杂。
方法三:提取属性数组并监听变化
使用 computed
提取所有目标属性,监听该数组的变化。
javascript
复制
下载
import { ref, watch, computed } from 'vue'; const items = ref([ { id: 1, name: 'A' }, { id: 2, name: 'B' } ]); const names = computed(() => items.value.map(item => item.name)); watch(names, (newNames, oldNames) => { newNames.forEach((newName, index) => { const oldName = oldNames[index]; if (oldName !== undefined && newName !== oldName) { console.log(`索引${index}的name变化: ${oldName} => ${newName}`); } }); });
优点:仅关注特定属性,减少比较范围。
缺点:无法直接关联到原对象,需通过索引处理。
// 提取金额数组
const totalArray = computed(() => ckDetail.value.map((item) => item.total));
// 监听金额数组
watch(
() => totalArray.value,
() => {
// 累计出库明细金额,得到出库总额
ckMaster.value.total = totalArray.value.reduce((pre, cur) => pre + Number(formatToRMB(cur)), 0);
}
);
总结
推荐方法一:适用于数组较小或变化不频繁的场景,简单快捷。
推荐方法二:适用于大型数组或需要精确控制的场景,但需处理动态监听。
方法三:适用于只需知道属性变化的位置,不关心具体对象的场景。