列表渲染
要学习列表的渲染,首先我们要知道js的遍历写法
提示
js可以遍历的结构包含对象、数组、Set 和 Map 结构、某些类似数组的对象(比如arguments对象、DOM NodeList 对象)、 Generator 对象,以及字符串等。
我们当前课程只需要学习遍历对象和数组即可
js常用遍历方法
for循环
for循环是一种常见的控制流结构,用于重复执行一段代码
遍历数组
const arr=[1,2,3,4,5];
for (let i = 0; i < arr.length; i++) {
console.log(arr[i]);
}遍历对象
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方法是一种常用的遍历数组元素的方式。它是数组对象的方法,接受一个回调函数作为参数,并对数组中的每个元素执行该回调函数
const arr=[1,2,3,4,5];
arr.forEach(f=>{
console.log(f);
})for of
for...of是JavaScript中的一种循环语法,用于遍历可迭代对象的元素。它提供了一种简洁的方式来遍历数组、字符串和其他可迭代对象,使代码更加易读和简洁。
const arr = [1, 2, 3, 4, 5];
for (let item of arr) {
console.log(item);
}for in
for...in是JavaScript中的一种循环语法,用于遍历对象的可枚举属性。它允许你迭代对象的属性,并执行相应的操作。
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 是迭代项的别名:
<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 也支持使用可选的第二个参数表示当前项的位置索引。
<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的作用域只在父级内部有效
<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作用域都可以访问到它的上级作用域:
<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() 的返回值来决定。
<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设置为一下数据看看执行效果
{
2: '我是第一个',
1: '我是第二个'
}遍历对象时,第二个参数代表属性名,第三个参数代表索引
<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 的取值范围重复多次。
<div v-for="n in 10" :key="n">{{ n }}</div>注意此处 n 的初值是从 1 开始而非 0。
<template> 上的 v-for
与模板上的 v-if 类似,你也可以在 <template> 标签上使用 v-for 来渲染一个包含多个元素的块。例如:
<ul>
<template v-for="item in items">
<li>{{ item.msg }}</li>
<li>xxx</li>
</template>
</ul>与v-if一起使用
当它们同时存在于一个节点上时,v-if 比 v-for 的优先级更高。这意味着 v-if 的条件将无法访问到 v-for 作用域内定义的变量别名:
<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解决
<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:
<div v-for="item in items" :key="item.id">
<!-- 内容 -->
</div>当你使用 <template v-for> 时,key 应该被放置在这个 <template> 容器上:
<template v-for="todo in todos" :key="todo.name">
<li>{{ todo.name }}</li>
</template>key 绑定的值期望是一个基础类型的值,例如字符串或 number 类型。不要用对象作为 v-for 的 key。关于 key attribute 的更多用途细节,请参阅 key API 文档。
经验之谈
如果我们的数据没有唯一值的时候,我们是可以使用索引作为v-for的key的
<div v-for="(item,index) in items" :key="index">
<!-- 内容 -->
</div>但是若是列表可以动态的修改,例如拖动改变顺序、删除某一行、在某一行的后面插入一行等等
就必须指定一个唯一标识,不然页面的渲染顺序会出问题