Vue基础入门10,列表渲染全攻略:v-for 遍历数组 / 对象与 key 的作用

2025博客之星年度评选已开启 10w+人浏览 1.8k人参与

在 Vue 开发中,列表渲染是高频使用的核心功能之一,而v-for指令则是实现这一功能的关键。它能够让我们便捷地遍历数组、对象等数据结构,将数据动态渲染成 DOM 元素。但如果使用不当,不仅可能导致页面渲染异常,还会引发性能问题。尤其是key的使用,看似简单,却是影响列表渲染效率和正确性的核心要点。本文将从v-for的基础用法到高级技巧,再到key的深层作用,全方位解析 Vue 列表渲染的精髓。

一、v-for 的基础用法:遍历数组

数组是前端开发中最常用的数据结构之一,v-for遍历数组的语法简洁直观,也是最基础的使用场景。

1. 基本遍历语法

v-for遍历数组时,基本语法为:v-for="item in array",其中item是数组中当前项的别名,array是要遍历的数组。

<template>
  <div>
    <h3>水果列表</h3>
    <ul>
      <!-- 遍历数组,渲染每一项 -->
      <li v-for="fruit in fruits">{{ fruit }}</li>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      fruits: ['苹果', '香蕉', '橙子', '葡萄']
    };
  }
};
</script>

上述代码会将fruits数组中的每一项渲染成<li>元素,最终在页面上显示出水果列表。

2. 获取索引值

如果需要用到数组的索引,可以使用扩展语法:v-for="(item, index) in array",其中index是当前项的索引(从 0 开始)。

<template>
  <div>
    <h3>水果列表(带索引)</h3>
    <ul>
      <!-- 同时获取项和索引 -->
      <li v-for="(fruit, index) in fruits">{{ index + 1 }}. {{ fruit }}</li>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      fruits: ['苹果', '香蕉', '橙子', '葡萄']
    };
  }
};
</script>

此时页面会显示带有序号的水果列表,索引的存在让我们能更灵活地处理数组项,比如实现 “删除第 n 项” 等功能。

3. 遍历数组对象

实际开发中,数组中的元素往往是对象(比如从后端获取的列表数据),v-for同样可以轻松遍历,只需通过.语法访问对象属性。

<template>
  <div>
    <h3>学生列表</h3>
    <table>
      <thead>
        <tr>
          <th>姓名</th>
          <th>年龄</th>
          <th>班级</th>
        </tr>
      </thead>
      <tbody>
        <!-- 遍历对象数组,访问属性 -->
        <tr v-for="student in students">
          <td>{{ student.name }}</td>
          <td>{{ student.age }}</td>
          <td>{{ student.class }}</td>
        </tr>
      </tbody>
    </table>
  </div>
</template>

<script>
export default {
  data() {
    return {
      students: [
        { name: '张三', age: 18, class: '高一(1)班' },
        { name: '李四', age: 17, class: '高一(2)班' },
        { name: '王五', age: 18, class: '高一(1)班' }
      ]
    };
  }
};
</script>

二、v-for 遍历对象

除了数组,v-for还支持遍历对象,这在处理键值对数据时非常有用(比如渲染表单的配置项)。

1. 基本遍历(获取值)

遍历对象的基本语法:v-for="value in object",其中value是对象当前属性的值。

<template>
  <div>
    <h3>用户信息(仅值)</h3>
    <ul>
      <li v-for="value in userInfo">{{ value }}</li>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      userInfo: {
        name: '张三',
        age: 18,
        gender: '男'
      }
    };
  }
};
</script>

2. 获取键和值

如果需要同时获取对象的键(属性名)和值,可以使用:v-for="(value, key) in object",其中key是当前属性的名称。

<template>
  <div>
    <h3>用户信息(键+值)</h3>
    <ul>
      <li v-for="(value, key) in userInfo">{{ key }}:{{ value }}</li>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      userInfo: {
        name: '张三',
        age: 18,
        gender: '男'
      }
    };
  }
};
</script>

3. 获取键、值和索引

还可以进一步获取遍历的索引:v-for="(value, key, index) in object"index是遍历的序号(从 0 开始)。

<template>
  <div>
    <h3>用户信息(键+值+索引)</h3>
    <ul>
      <li v-for="(value, key, index) in userInfo">{{ index + 1 }}. {{ key }}:{{ value }}</li>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      userInfo: {
        name: '张三',
        age: 18,
        gender: '男'
      }
    };
  }
};
</script>

注意:Vue 在遍历对象时,会按Object.keys()的结果遍历,不能保证遍历顺序与对象属性的定义顺序一致(在 ES6 之前,对象属性的顺序是不确定的),如果需要固定顺序,建议将对象转换为数组处理。

三、v-for 的特殊用法:遍历数字

v-for还支持遍历数字,语法为:v-for="n in number",其中n从 1 开始到number结束。这在需要渲染固定数量的元素时很方便(比如分页器的页码、星级评分的星星)。

<template>
  <div>
    <h3>星级评分(5星)</h3>
    <span v-for="n in 5" :key="n">★</span>
  </div>
</template>

上述代码会渲染 5 个星星符号,实现简单的星级展示效果。

四、key 的核心作用:为什么必须用?

在使用v-for时,Vue 官方强烈建议为每个遍历项绑定一个唯一的key属性。很多开发者会忽略这一点,或者随意使用索引作为key,这可能会导致意想不到的问题。接下来我们深入解析key的作用。

1. Vue 的虚拟 DOM 与 diff 算法

Vue 通过虚拟 DOM(VNode)来描述真实 DOM,当数据发生变化时,Vue 会生成新的虚拟 DOM,然后通过diff 算法对比新旧虚拟 DOM 的差异,只更新差异部分到真实 DOM,从而提升性能。

在处理列表时,diff 算法默认会采用 “就地更新” 的策略:如果列表项的顺序发生变化,Vue 不会移动 DOM 元素的位置,而是直接更新 DOM 元素的内容,使其匹配新的列表项。这种策略在简单场景下没问题,但在列表项包含复杂组件、表单元素或有状态的 DOM 时,会导致渲染异常。

2. key 的作用:标识节点的唯一性

key的本质是虚拟 DOM 节点的唯一标识,Vue 通过key来判断新旧虚拟 DOM 节点是否为同一个节点。当列表数据发生变化时,Vue 会根据key对比新旧节点:

  • 如果key相同,说明是同一个节点,Vue 会复用该节点,只更新节点的属性;
  • 如果key不同,说明是新节点,Vue 会创建新的 DOM 节点并插入到页面中,或者移除旧的节点。

这一机制避免了 “就地更新” 的缺陷,保证了列表渲染的正确性和效率。

3. 反例:使用索引作为 key 的问题

很多开发者习惯用数组的索引作为key,比如:v-for="(item, index) in list" :key="index"。在列表项的顺序不发生变化(仅增删最后一项)时,这样做暂时没问题,但如果列表项的顺序发生变化(比如排序、删除中间项、插入新项),就会出现问题。

示例:使用索引作为 key 的问题

<template>
  <div>
    <button @click="reverseList">反转列表</button>
    <ul>
      <li v-for="(item, index) in list" :key="index">
        {{ item }}
        <input type="text" placeholder="输入内容">
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      list: ['A', 'B', 'C']
    };
  },
  methods: {
    reverseList() {
      this.list.reverse();
    }
  }
};
</script>

操作步骤:

  1. 在 A、B、C 对应的输入框中分别输入 1、2、3;
  2. 点击 “反转列表” 按钮,列表变为 C、B、A,但输入框中的内容却还是 1、2、3,并没有跟着列表项反转。

原因分析

  • 反转前列表的key是 0 (A)、1 (B)、2 (C);
  • 反转后列表的key是 0 (C)、1 (B)、2 (A);
  • Vue 根据key对比,认为key=0的节点还是原来的节点,只是内容从 A 变成了 C,因此复用了该节点,输入框的内容也被保留了下来,导致输入框内容与列表项不匹配。

4. 正确做法:使用唯一标识作为 key

正确的做法是使用列表项的唯一标识作为key,比如后端返回的id、唯一的编号等。这样即使列表项的顺序发生变化,Vue 也能准确识别每个节点,正确地创建、复用或移除 DOM 节点。

修复后的示例

<template>
  <div>
    <button @click="reverseList">反转列表</button>
    <ul>
      <li v-for="item in list" :key="item.id">
        {{ item.name }}
        <input type="text" placeholder="输入内容">
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      list: [
        { id: 1, name: 'A' },
        { id: 2, name: 'B' },
        { id: 3, name: 'C' }
      ]
    };
  },
  methods: {
    reverseList() {
      this.list.reverse();
    }
  }
};
</script>

此时再操作输入框并反转列表,输入框的内容会跟着列表项一起反转,因为每个列表项的key是唯一的id,Vue 能正确识别节点的变化。

五、v-for 的注意事项与性能优化

1. 避免在 v-for 中使用 v-if

Vue 官方不建议在同一个元素上同时使用v-forv-if,因为v-for的优先级高于v-if,这意味着每次遍历都会执行v-if的判断,导致性能损耗。

不良示例

<!-- 不推荐:v-for和v-if同时使用 -->
<li v-for="item in list" :key="item.id" v-if="item.isShow">
  {{ item.name }}
</li>

优化方案

  • 如果需要过滤列表项,先在计算属性中过滤数据,再遍历:
<template>
  <li v-for="item in filteredList" :key="item.id">
    {{ item.name }}
  </li>
</template>

<script>
export default {
  computed: {
    filteredList() {
      return this.list.filter(item => item.isShow);
    }
  }
};
</script>
  • 如果需要隐藏整个列表,将v-if绑定到父元素上:
<ul v-if="isShowList">
  <li v-for="item in list" :key="item.id">
    {{ item.name }}
  </li>
</ul>

2. 列表数据的更新注意事项

Vue 的响应式系统对数组的某些操作是无法检测的,比如:

  • 直接通过索引修改数组项:this.list[0] = newItem
  • 修改数组的长度:this.list.length = 0

如果需要更新列表数据,应使用 Vue 提供的变异方法(pushpopshiftunshiftsplicesortreverse),或者替换整个数组(filtermap等)。

<script>
export default {
  methods: {
    updateItem() {
      // 正确:使用splice修改数组项
      this.list.splice(0, 1, newItem);
      // 正确:替换整个数组
      this.list = this.list.map(item => item.id === 1 ? newItem : item);
    }
  }
};
</script>

3. 大列表的性能优化

如果列表数据量很大(比如上千条),渲染和更新时会出现性能问题。可以采用以下优化方案:

  • 分页加载:只渲染当前页的列表项,用户翻页时再加载下一页数据;
  • 虚拟列表:只渲染可视区域内的列表项,滚动时动态替换内容(可使用vue-virtual-scroller等第三方库);
  • 使用track-by(Vue1.x)/key(Vue2.x+):确保节点复用的效率。

六、总结

v-for是 Vue 实现列表渲染的核心指令,它支持遍历数组、对象、数字等数据结构,语法灵活且易用。而key作为列表项的唯一标识,是保证列表渲染正确性和性能的关键,务必使用唯一的业务标识(如 id)作为 key,避免使用索引

同时,在使用v-for时,还需要注意避免与v-if同时使用、正确更新列表数据、优化大列表的渲染性能等问题。掌握这些知识点,才能在实际开发中高效、稳定地使用列表渲染功能,写出更优质的 Vue 代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

canjun_wen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值