From 24786f25f485383dbaca53004898cc812cf4954f Mon Sep 17 00:00:00 2001 From: bunny <1319900154@qq.com> Date: Sat, 14 Jun 2025 21:54:37 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=89=20Vue2=20=E6=95=B0=E7=BB=84?= =?UTF-8?q?=E5=8F=98=E5=8C=96=E7=9B=91=E6=B5=8B=E5=8E=9F=E7=90=86=E4=B8=8E?= =?UTF-8?q?=E5=AE=9E=E6=88=98=E6=8C=87=E5=8D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../12-Vue监测数据的原理_数组.html | 61 ++++++ .../12-Vue监测数据的原理_数组.md | 175 ++++++++++++++++++ 2 files changed, 236 insertions(+) create mode 100644 vue2-tutorials/import-script/12-Vue监测数据的原理_数组.html create mode 100644 vue2-tutorials/import-script/12-Vue监测数据的原理_数组.md diff --git a/vue2-tutorials/import-script/12-Vue监测数据的原理_数组.html b/vue2-tutorials/import-script/12-Vue监测数据的原理_数组.html new file mode 100644 index 0000000..f04a030 --- /dev/null +++ b/vue2-tutorials/import-script/12-Vue监测数据的原理_数组.html @@ -0,0 +1,61 @@ + + + + + + + Vue监测数据的原理_数组 + + + +
+

列表过滤

+ + + +
+ + + + diff --git a/vue2-tutorials/import-script/12-Vue监测数据的原理_数组.md b/vue2-tutorials/import-script/12-Vue监测数据的原理_数组.md new file mode 100644 index 0000000..dfabf4b --- /dev/null +++ b/vue2-tutorials/import-script/12-Vue监测数据的原理_数组.md @@ -0,0 +1,175 @@ +# Vue2 数组变化监测原理与实战指南 + +## 一、核心原理 + +Vue2 通过重写数组的变异方法实现对数组变化的监测,这是其响应式系统的关键部分。当直接通过索引修改数组元素时(如 `arr[0] = newValue`),Vue 无法自动检测到这种变化。 + +## 二、代码示例解析 + +```html +
+

列表更新演示

+ + +
+ + +``` + +## 三、响应式数组操作方法 + +### 1. Vue 包装的变异方法 + +Vue 重写了以下数组方法,使其能触发视图更新: + +- `push()` / `pop()` +- `shift()` / `unshift()` +- `splice()` +- `sort()` / `reverse()` + +### 2. 特殊场景处理 + +| 场景 | 正确方法 | 错误方法 | +| -------- | ------------------------------- | ----------------------- | +| 修改元素 | `Vue.set(arr, index, newValue)` | `arr[index] = newValue` | +| 添加元素 | `arr.splice(index, 0, newItem)` | `arr[index] = newItem` | +| 删除元素 | `arr.splice(index, 1)` | `delete arr[index]` | + +### 3. 注意事项 + +- 使用 `filter()`、`concat()` 等非变异方法时,需要用返回的新数组替换原数组 +- 嵌套数组需要深度观测 + +## 四、原理深入 + +### 1. 实现机制 + +Vue 通过以下步骤实现数组响应式: + +1. 拦截数组原型方法 +2. 在方法执行后通知依赖更新 +3. 对新增元素进行响应式处理 + +### 2. 源码关键部分 + +```javascript +// 简化版的数组响应式实现 +const arrayProto = Array.prototype; +const arrayMethods = Object.create(arrayProto); + +const methodsToPatch = [ + "push", + "pop", + "shift", + "unshift", + "splice", + "sort", + "reverse", +]; + +methodsToPatch.forEach(function (method) { + const original = arrayProto[method]; + def(arrayMethods, method, function mutator(...args) { + const result = original.apply(this, args); + const ob = this.__ob__; + let inserted; + switch (method) { + case "push": + case "unshift": + inserted = args; + break; + case "splice": + inserted = args.slice(2); + break; + } + if (inserted) ob.observeArray(inserted); + ob.dep.notify(); // 通知更新 + return result; + }); +}); +``` + +## 五、最佳实践 + +### 1. 性能优化 + +- 大数据量操作时使用 `Vue.nextTick` 批量更新 +- 避免在模板中直接操作复杂数组计算 + +### 2. 代码规范 + +- 统一使用 `Vue.set` 或 `splice` 修改数组 +- 为 `v-for` 设置合适的 `key` + +### 3. 扩展方法 + +```javascript +// 安全的数组修改方法 +function safeArrayUpdate(arr, index, newValue) { + if (Array.isArray(arr)) { + return Vue.set(arr, index, newValue); + } + throw new Error("Target is not an array"); +} +``` + +## 六、常见问题解决方案 + +1. **为什么我的数组修改不生效?** + + - 检查是否使用了 Vue 能检测的变异方法 + - 确认没有直接修改数组长度(如 `arr.length = 0`) + +2. **如何强制更新数组?** + + ```javascript + // 方法1:使用空splice触发更新 + this.list.splice(); + + // 方法2:使用Vue.set + Vue.set(this.list, 0, this.list[0]); + ``` + +3. **对象数组中的对象属性修改** + - 直接修改对象属性可以触发更新(因为对象是响应式的) + ```javascript + // 这是有效的 + this.list[0].name = "new name"; + ```