Skip to content

列表渲染

要学习列表的渲染,首先我们要知道js的遍历写法

提示

js可以遍历的结构包含对象、数组、Set 和 Map 结构、某些类似数组的对象(比如arguments对象、DOM NodeList 对象)、 Generator 对象,以及字符串等。

我们当前课程只需要学习遍历对象和数组即可

js常用遍历方法

for循环

for循环是一种常见的控制流结构,用于重复执行一段代码

遍历数组

js
const arr=[1,2,3,4,5];
for (let i = 0; i < arr.length; i++) {
  console.log(arr[i]);
}

遍历对象

js
const obj = { a: 1, b: 2, c: 3 };
const obj_keys = Object.keys(obj);
console.log(obj_keys);
for (let i = 0; i < obj_keys.length; i++) {
  const key = obj_keys[i];
  const value = obj[key];
  console.log(key + ": " + value);
}

forEach

forEach方法是一种常用的遍历数组元素的方式。它是数组对象的方法,接受一个回调函数作为参数,并对数组中的每个元素执行该回调函数

js
const arr=[1,2,3,4,5];
arr.forEach(f=>{
    console.log(f);
})

for of

for...of是JavaScript中的一种循环语法,用于遍历可迭代对象的元素。它提供了一种简洁的方式来遍历数组、字符串和其他可迭代对象,使代码更加易读和简洁。

js
const arr = [1, 2, 3, 4, 5];

for (let item of arr) {
  console.log(item);
}

for in

for...in是JavaScript中的一种循环语法,用于遍历对象的可枚举属性。它允许你迭代对象的属性,并执行相应的操作。

js
const obj = { a: 1, b: 2, c: 3 };
for (let key in obj) {
    const value = obj[key];
    console.log(key + ": " + value);
}

注意

虽然for...in循环可以用于遍历数组,但它并不是最佳选择,因为它不仅遍历数组的元素,还会遍历数组的所有可枚举属性。这可能导致意外的结果,因为数组的索引被视为对象的属性。

v-for​

在vue中我们可以使用v-for指令基于一个数组来渲染一个列表。v-for 指令的值需要使用 item in items 形式的特殊语法,其中 items 是源数据的数组,而 item 是迭代项的别名:

vue
<template>
  <div>
    <div v-for="item in arr" :key="item.name">
      {{ `姓名是${item.name},年龄是${item.age}` }}
    </div>
  </div>
</template>
<script setup lang="ts">
import { ref } from 'vue';

const arr = ref([{
  name: '李雷',
  age: 21
}, {
  name: '韩梅梅',
  age: 18
}])
</script>

v-for 块中可以完整地访问父作用域内的属性和变量。v-for 也支持使用可选的第二个参数表示当前项的位置索引。

vue
<template>
  <div>
    <div v-for="(item, index) in arr" :key="item.name">
      {{ `姓名是${item.name},年龄是${item.age},索引是${index}` }}
    </div>
  </div>
</template>
<script setup lang="ts">
import { ref } from 'vue';

const arr = ref([{
  name: '李雷',
  age: 21
}, {
  name: '韩梅梅',
  age: 18
}])
</script>

v-for的作用域只在父级内部有效

vue
<template>
  <div>
    <div v-for="(item, index) in arr" :key="item.name">
      {{ `姓名是${item.name},年龄是${item.age},索引是${index}` }}
    </div>
    <!-- 下面的item是无效的 -->
    测试:{{ item }}
  </div>
</template>
<script setup lang="ts">
import { ref } from 'vue';

const arr = ref([{
  name: '李雷',
  age: 21
}, {
  name: '韩梅梅',
  age: 18
}])
</script>

嵌套写法

每个v-for作用域都可以访问到它的上级作用域:

vue
<template>
  <div>
    <div v-for="class_item in arr" :key="class_item.class">
      <div>班级是{{ class_item.class }},学生有:</div>
      <div v-for="(students_item, students_index) in class_item.students" :key="students_item.name">
        {{ `姓名是${students_item.name},年龄是${students_item.age},索引是${students_index},属于班级${class_item.class}` }}
      </div>
    </div>
  </div>
</template>
<script setup lang="ts">
import { ref } from 'vue';

const arr = ref(
  [{
    class: 'A',
    students: [{
      name: '李雷',
      age: 21
    }, {
      name: '韩梅梅',
      age: 18
    }]
  },
  {
    class: 'B',
    students: [{
      name: '张三',
      age: 19
    }, {
      name: '李四',
      age: 20
    }]
  }]
)
</script>

遍历对象

我们也可以使用 v-for 来遍历一个对象的所有属性。遍历的顺序会基于对该对象调用 Object.keys() 的返回值来决定。

vue
<template>
  <div>
    <div v-for="value in obj" :key="value">
      value是{{ value }}
    </div>
  </div>
</template>
<script setup lang="ts">
import { ref } from 'vue';

const obj = ref(
  {
    name: '李雷',
    age: 21
  }
)
</script>

TIP

js的对象是无序的,就像java的dict一样,所以我们上面说遍历的顺序会基于对该对象调用 Object.keys() 的返回值来决定

你可以把obj设置为一下数据看看执行效果

js
  {
    2: '我是第一个',
    1: '我是第二个'
  }

遍历对象时,第二个参数代表属性名,第三个参数代表索引

vue
<template>
  <div>
    <div v-for="(value, key, index) in arr" :key="value">
      value是{{ value }};key是{{ key }};索引是{{ index }}
    </div>
  </div>
</template>
<script setup lang="ts">
import { ref } from 'vue';

const arr = ref(
  {
    name: '李雷',
    age: 21
  }
)
</script>

of or in?

v-for里面,无论你使用 of 还是 in 关键字,它们只是语法上的不同,不会影响遍历的结果

当然了,要是想增加代码的可读性,你可以用of来遍历数组,用in遍历对象

这更接近 JavaScript 的语法

v-for里使用范围值​

v-for可以直接接受一个整数值。在这种用例中,会将该模板基于 1...n 的取值范围重复多次。

vue
   <div v-for="n in 10" :key="n">{{ n }}</div>

注意此处 n 的初值是从 1 开始而非 0。

<template> 上的 v-for​

与模板上的 v-if 类似,你也可以在 <template> 标签上使用 v-for 来渲染一个包含多个元素的块。例如:

html
<ul>
  <template v-for="item in items">
    <li>{{ item.msg }}</li>
    <li>xxx</li>
  </template>
</ul>

v-if一起使用

当它们同时存在于一个节点上时,v-ifv-for 的优先级更高。这意味着 v-if 的条件将无法访问到 v-for 作用域内定义的变量别名:

vue
<template>
  <div>
    <div v-for="item in arr" :key="item.name" v-if="item.age > 18">
      {{ `姓名是${item.name},年龄是${item.age}` }}
    </div>
  </div>
</template>
<script setup lang="ts">
import { ref } from 'vue';

const arr = ref([{
  name: '李雷',
  age: 21
}, {
  name: '韩梅梅',
  age: 18
}])
</script>

上面代码中v-if无法item的值

这种情况我们可以使用template解决

vue
<template>
  <div>
    <template v-for="item in arr" :key="item.name">
      <div v-if="item.age > 18">
        {{ `姓名是${item.name},年龄是${item.age}` }}
      </div>
    </template>

  </div>
</template>
<script setup lang="ts">
import { ref } from 'vue';

const arr = ref([{
  name: '李雷',
  age: 21
}, {
  name: '韩梅梅',
  age: 18
}])
</script>

通过 key 管理状态

Vue 默认按照“就地更新”的策略来更新通过 v-for 渲染的元素列表。当数据项的顺序改变时,Vue 不会随之移动 DOM 元素的顺序,而是就地更新每个元素,确保它们在原本指定的索引位置上渲染。

默认模式是高效的,但只适用于列表渲染输出的结果不依赖子组件状态或者临时 DOM 状态 (例如表单输入值) 的情况

为了给 Vue 一个提示,以便它可以跟踪每个节点的标识,从而重用和重新排序现有的元素,你需要为每个元素对应的块提供一个唯一的 key attribute:

vue
<div v-for="item in items" :key="item.id">
  <!-- 内容 -->
</div>

当你使用 <template v-for> 时,key 应该被放置在这个 <template> 容器上:

vue
<template v-for="todo in todos" :key="todo.name">
  <li>{{ todo.name }}</li>
</template>

key 绑定的值期望是一个基础类型的值,例如字符串或 number 类型。不要用对象作为 v-for 的 key。关于 key attribute 的更多用途细节,请参阅 key API 文档

经验之谈

如果我们的数据没有唯一值的时候,我们是可以使用索引作为v-forkey

vue
<div v-for="(item,index) in items" :key="index">
  <!-- 内容 -->
</div>

但是若是列表可以动态的修改,例如拖动改变顺序、删除某一行、在某一行的后面插入一行等等

就必须指定一个唯一标识,不然页面的渲染顺序会出问题