MST

星途 面试题库

面试题:Vue中响应式数据更新机制下,数组变更检测的原理及方法

在Vue的响应式数据更新机制里,数组的变化有时不能被自动检测到。请阐述Vue是如何检测数组变更的原理,并且说明有哪些方法可以确保数组变化能触发视图更新。
24.3万 热度难度
前端开发Vue

知识考点

AI 面试

面试题答案

一键面试

Vue检测数组变更的原理

Vue 不能检测以下数组的变动:

  1. 当你利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue
  2. 当你修改数组的长度时,例如:vm.items.length = newLength

Vue 内部通过覆盖数组的原型方法,使用了被称为“变异方法”来检测数组变化。Vue 将 Array.prototype 上的 7 个变异方法(pushpopshiftunshiftsplicesortreverse)进行了包裹,当调用这些变异方法时,不仅会改变数组本身,还会触发视图更新。

确保数组变化能触发视图更新的方法

  1. 使用变异方法
    • push:向数组的末尾添加一个或多个元素,并返回新的长度。例如:
    let arr = [1, 2, 3];
    arr.push(4);
    
    • pop:删除并返回数组的最后一个元素。例如:
    let arr = [1, 2, 3];
    arr.pop();
    
    • shift:删除并返回数组的第一个元素。例如:
    let arr = [1, 2, 3];
    arr.shift();
    
    • unshift:向数组的开头添加一个或多个元素,并返回新的长度。例如:
    let arr = [1, 2, 3];
    arr.unshift(0);
    
    • splice:用于插入、删除或替换数组的元素。例如,删除元素:
    let arr = [1, 2, 3];
    arr.splice(1, 1); // 从索引1开始删除1个元素
    
    • sort:对数组的元素进行排序。例如:
    let arr = [3, 1, 2];
    arr.sort();
    
    • reverse:颠倒数组中元素的顺序。例如:
    let arr = [1, 2, 3];
    arr.reverse();
    
  2. 使用 Vue.set 或 this.$set
    • 当需要通过索引直接设置一个数组项时,可以使用 Vue.set(在全局引入 Vue 时) 或 this.$set(在组件内部)。例如:
    import Vue from 'vue';
    let arr = [1, 2, 3];
    Vue.set(arr, 1, 5); // 将索引为1的元素设置为5
    
    在组件内:
    export default {
      data() {
        return {
          arr: [1, 2, 3]
        };
      },
      methods: {
        updateArray() {
          this.$set(this.arr, 1, 5);
        }
      }
    };
    
  3. 替换数组
    • 可以通过创建一个新的数组来替换原来的数组,这样也能触发视图更新。例如:
    let arr = [1, 2, 3];
    arr = arr.filter(item => item!== 2);
    
    在 Vue 组件中:
    <template>
      <div>
        <ul>
          <li v - for="(item, index) in arr" :key="index">{{item}}</li>
        </ul>
        <button @click="updateArray">Update Array</button>
      </div>
    </template>
    
    <script>
    export default {
      data() {
        return {
          arr: [1, 2, 3]
        };
      },
      methods: {
        updateArray() {
          this.arr = this.arr.filter(item => item!== 2);
        }
      }
    };
    </script>