MST
星途 面试题库

面试题:Vue Fragment 中如何通过合理使用 key 来优化性能

在 Vue Fragment 场景下,阐述 key 属性的作用以及如何正确设置 key 来提升渲染性能,举例说明不同 key 设置可能带来的渲染差异。
18.3万 热度难度
前端开发Vue

知识考点

AI 面试

面试题答案

一键面试

key 属性的作用

  1. 高效更新虚拟 DOM:Vue 在更新 DOM 时,会对比新旧虚拟 DOM 树。当节点处于 Fragment 中时,key 作为节点的唯一标识,能帮助 Vue 快速识别哪些节点发生了变化,哪些节点需要更新、添加或删除。避免不必要的 DOM 操作,从而提升渲染性能。例如,在一个列表渲染的 Fragment 中,如果没有 key,Vue 可能会复用错误的 DOM 元素,导致显示异常。
  2. 组件状态管理:对于包含在 Fragment 中的组件,key 可以影响组件的创建和销毁。当 key 变化时,Vue 会重新创建组件实例,而不是复用之前的实例。这在一些需要重置组件状态的场景下非常有用。

正确设置 key 提升渲染性能的方法

  1. 使用唯一且稳定的值:在列表渲染场景中,最好使用数据项中具有唯一性的标识作为 key。例如,如果列表是用户列表,每个用户有唯一的 id,那么使用 id 作为 key 是最佳选择。如:
<template>
  <Fragment>
    <div v-for="user in users" :key="user.id">
      {{ user.name }}
    </div>
  </Fragment>
</template>

<script>
export default {
  data() {
    return {
      users: [
        { id: 1, name: 'Alice' },
        { id: 2, name: 'Bob' }
      ]
    };
  }
};
</script>
  1. 避免使用索引作为 key:虽然使用索引作为 key 看似简单,但在列表发生增删改操作时,会导致 Vue 做出错误的 DOM 操作判断。例如:
<template>
  <Fragment>
    <div v-for="(user, index) in users" :key="index">
      {{ user.name }}
    </div>
  </Fragment>
</template>

<script>
export default {
  data() {
    return {
      users: [
        { name: 'Alice' },
        { name: 'Bob' }
      ]
    };
  },
  methods: {
    addUser() {
      this.users.unshift({ name: 'Charlie' });
    }
  }
};
</script>

当调用 addUser 方法时,由于 key 是索引,Vue 会认为原来索引为 0 的 Alice 变成了 Charlie,索引为 1 的 Bob 变成了 Alice,从而错误地复用 DOM 元素,导致性能问题和显示异常。

不同 key 设置带来的渲染差异

  1. 使用唯一标识作为 key:假设我们有一个任务列表,任务有唯一 taskId
<template>
  <Fragment>
    <div v-for="task in tasks" :key="task.taskId">
      {{ task.title }}
    </div>
  </Fragment>
</template>

<script>
export default {
  data() {
    return {
      tasks: [
        { taskId: 1, title: 'Task 1' },
        { taskId: 2, title: 'Task 2' }
      ]
    };
  },
  methods: {
    updateTask() {
      this.tasks[0].title = 'Updated Task 1';
    }
  }
};
</script>

当调用 updateTask 方法时,Vue 能准确识别出是 taskId 为 1 的任务发生了变化,仅更新对应的 DOM 元素,渲染高效且准确。

  1. 使用索引作为 key:同样是上述任务列表,若使用索引作为 key:
<template>
  <Fragment>
    <div v-for="(task, index) in tasks" :key="index">
      {{ task.title }}
    </div>
  </Fragment>
</template>

<script>
export default {
  data() {
    return {
      tasks: [
        { title: 'Task 1' },
        { title: 'Task 2' }
      ]
    };
  },
  methods: {
    addTask() {
      this.tasks.unshift({ title: 'New Task' });
    }
  }
};
</script>

当调用 addTask 方法时,Vue 会错误地认为所有任务的位置都发生了变化,对所有 DOM 元素进行更新,而不是仅添加新的 DOM 元素,导致不必要的性能开销。