Vue3中ref数组的监听实现方式
作者:BillKu
Vue3中监听ref定义的数组,需根据监听需求选择合适的监听方法,对于空数组,推荐使用深度监听来捕捉数组内部变化,同时,确保修改数组的方式是响应式的,以保证监听器能正常工作,根据具体需求,可以选择直接深度监听、监听数组长度变化或提取属性监听等方案
在Vue 3中,监听一个由 ref 定义的数组【特别是像你这样初始化为空数组的情况 const jjdData = ref<JJD[]>([])】,关键在于理解你希望监听何种类型的变化。
下面用一个表格汇总主要的监听场景和方法,方便你快速了解:
| 监听场景 | 推荐写法 | 说明 |
|---|---|---|
| 数组被整体替换 | watch(jjdData, (newVal) => { ... }) | 监听整个数组的引用变化。 |
| 数组内部变化(增删元素)及元素自身变化 | watch(jjdData, (newVal) => { ... }, { deep: true }) | 最常用。深度监听,可响应数组方法和元素属性的变化。 |
| 仅监听数组长度的变化 | watch(() => jjdData.value.length, (newLen) => { ... }) | 只关心元素数量的增减,不关心具体内容变化。 |
| 监听数组中特定对象属性的变化 | watch(() => jjdData.value.map(item => item.someProperty), (newVals) => { ... }) | 例如,只关心每个 JJD 对象的 id 或 name 属性是否变化。 |
监听器的详细写法与注意事项
1.基本监听与深度监听
对于你的 jjdData,如果它最初是空数组,然后在组件挂载后被赋值(例如通过异步请求),你需要使用深度监听来捕捉数组本身以及其内部对象元素的变化。
import { watch } from 'vue';
// 深度监听,可以响应数组替换、数组方法调用以及对象元素属性的变化
watch(
jjdData,
(newArray, oldArray) => {
console.log('数组发生了变化', newArray);
// 在这里执行你的副作用逻辑
},
{ deep: true } // 关键配置
);注意:
当监听 reactive 定义的响应式数据时,会强制开启深度监视,但对于 ref 定义的数组,需要显式配置 deep: true。
使用 deep: true 时,oldArray 可能与 newArray 相同,因为它们指向同一个响应式代理对象。
2.提取属性进行监听
如果只想监听数组内对象某些特定属性的集合变化,可以使用计算属性提取后再监听,这有助于减少不必要的回调。
import { watch, computed } from 'vue';
// 提取出所有需要监听的属性,组成一个新数组
const somePropertyList = computed(() => jjdData.value.map(item => item.someProperty));
watch(somePropertyList, (newValues, oldValues) => {
// 比较 newValues 和 oldValues 来确定具体哪个索引的属性发生了变化
console.log('某个对象的someProperty发生了变化', newValues);
});
// 或者使用getter函数
watch(
() => jjdData.value.map(item => item.someProperty),
(newVals, oldVals) => { ... }
);3.动态管理监听器(适用于大型动态数组)
对于频繁增删元素的大型数组,如果需要为每个元素的特定属性建立单独的监听器,可以考虑动态管理监听器,但通常复杂度较高。
import { watch, onScopeDispose } from 'vue';
const stops = new Map(); // 用来存储每个监听器的停止函数
// 监听整个数组的变化,以管理针对每个元素的监听器
watch(
() => [...jjdData.value],
(newArr, oldArr) => {
// 逻辑:对比新老数组,为新增元素创建监听器,为删除的元素移除监听器
// ... (具体实现可参考搜索结果中的示例:cite[2])
},
{ deep: true }
);
// 组件卸载时清理所有监听器
onScopeDispose(() => {
stops.forEach(stop => stop());
stops.clear();
});除非有非常精确的需求,否则更推荐使用前面提到的深度监听或提取属性监听的方法。
确保响应式变化的注意事项
为了让监听正常生效,你需要确保修改数组的方式是响应式的:
- 变更数组本身:推荐使用数组的变更方法,如
push,pop,splice,shift,unshift等,或者直接对整个数组进行赋值(例如jjdData.value = newArray)。 - 修改数组内的对象元素:直接通过索引修改对象属性(例如
jjdData.value[0].name = 'new value')在Vue 3的响应式系统下是可以被deep: true检测到的。但更推荐的做法是创建一个新对象进行替换,以保证变化的可追踪性,例如jjdData.value[0] = { ...jjdData.value[0], name: 'new value' }。
如何选择监听方案
- 对于大多数情况,直接使用
deep: true进行深度监听是最简单直接的选择。 - 如果只关心数组是否被整体替换,或者只关心数组长度的变化,可以使用非深度监听。
- 如果数组很大,或者只关心里面对象的某一个特定属性,使用提取属性并监听的方式性能会更优。
- 尽量避免在大型动态数组上为每个元素单独创建监听器,除非确有必要,因为管理起来比较复杂。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
