Vue 2 中如何监控数组的变化 Vue 2
约 762 字大约 3 分钟
2025-07-15
在 Vue 2 中监听数组长度变化需要特别注意,因为 Vue 2 的响应式系统基于 Object.defineProperty
,无法直接检测数组索引和 length 属性的变化。以下是几种有效的实现方法:
1、使用 Vue.set()
、this.$set()
或数组方法修改数组
一般情况下,我们不会去刻意的将一个数组添加到 watch 上,但是如果确保,我们对数组做了修改能及时生效的话,我们可以使用 Vue.set()
、this.$set()
或数组方法修改数组。
// 正确 - 使用Vue能检测到的方法
this.myArray.push(newItem); // 触发更新
this.myArray.splice(index, 1); // 触发更新
Vue.set(this.myArray, index, newValue); // 触发更新
this.$set(this.myArray, index, newValue); // 触发更新
// 错误 - 不会触发更新
this.myArray[index] = newValue;
this.myArray.length = newLength;
2、使用 $watch
监听 length 属性(推荐)
export default {
data() {
return {
myArray: [1, 2, 3],
};
},
created() {
// 方法1:直接监听length
this.$watch(
() => this.myArray.length,
(newLength, oldLength) => {
console.log(`数组长度从 ${oldLength} 变为 ${newLength}`);
}
);
// 方法2:使用字符串路径
this.$watch("myArray.length", (newLength, oldLength) => {
console.log(`数组长度从 ${oldLength} 变为 ${newLength}`);
});
},
};
原理
- Vue 会创建一个 Watcher 来追踪数组的 length 属性
- 当使用数组方法修改数组时,Vue 封装的方法会通知依赖更新
3、使用计算属性 + watch
export default {
data() {
return {
myArray: [1, 2, 3],
};
},
computed: {
arrayLength() {
return this.myArray.length;
},
},
watch: {
arrayLength(newLen, oldLen) {
console.log(`数组长度从 ${oldLen} 变为 ${newLen}`);
},
},
};
4、重写数组方法(扩展原型)
如果需要更细粒度的控制,可以扩展数组方法:
export default {
data() {
return {
myArray: this.createReactiveArray([1, 2, 3]),
};
},
methods: {
createReactiveArray(array) {
const reactiveArray = array.slice();
// 保存原始方法
const arrayMethods = [
"push",
"pop",
"shift",
"unshift",
"splice",
"sort",
"reverse",
];
const originalMethods = {};
arrayMethods.forEach((method) => {
originalMethods[method] = Array.prototype[method];
Object.defineProperty(reactiveArray, method, {
enumerable: false,
configurable: true,
writable: true,
value: function (...args) {
const result = originalMethods[method].apply(this, args);
console.log(`数组长度变为: ${this.length}`);
// 手动触发视图更新
this.__ob__.dep.notify();
return result;
},
});
});
return reactiveArray;
},
},
};
5. 深度监听整个数组
export default {
watch: {
myArray: {
handler(newVal, oldVal) {
console.log("数组变化,新长度:", newVal.length);
},
deep: true, // 深度监听
},
},
};
注意事项
Vue 2 的响应式限制:
- 直接通过索引设置项 (
array[index] = value
) 不会触发视图更新 - 直接修改 length 属性 (
array.length = 0
) 不会触发视图更新
- 直接通过索引设置项 (
性能考虑:
- 深度监听 (
deep: true
) 对大型数组可能有性能影响 - 考虑只在必要时使用深度监听
- 深度监听 (
最佳实践:
- 优先使用 Vue 提供的数组方法 (
push
,pop
,shift
,unshift
,splice
,sort
,reverse
) - 对于索引操作,使用
Vue.set
或this.$set
- 优先使用 Vue 提供的数组方法 (
完整示例
export default {
data() {
return {
items: ["a", "b", "c"],
};
},
created() {
// 监听数组长度变化
this.$watch("items.length", (newLen, oldLen) => {
console.log(`长度变化: ${oldLen} → ${newLen}`);
});
},
methods: {
addItem() {
this.items.push("new"); // 会触发监听
},
removeItem() {
this.items.pop(); // 会触发监听
},
updateItem(index, newValue) {
this.$set(this.items, index, newValue); // 会触发监听
},
badUpdate(index, newValue) {
this.items[index] = newValue; // 不会触发监听!
},
},
};
在 Vue 2 中,通过以上方法可以可靠地监听数组长度的变化,但必须注意使用 Vue 能够检测到的方式修改数组。
更新日志
2025/8/24 08:17
查看所有更新日志
e7112
-1于