08、Vue.js 3 —— 列表渲染
v-for 遍历数组
v-for 指令需要使用 item in items 形式的特殊语法,其中 items 是源数据数组,而 item 则是被迭代的数组元素的别名。
<ul id="array-with-index"> <li v-for="(item, index) in items"> {{ parentMessage }} - {{ index }} - {{ item.message }} </li> </ul>
Vue.createApp({ data() { return { parentMessage: 'Parent', items: [{ message: 'Foo' }, { message: 'Bar' }] } } }).mount('#array-with-index')
你也可以用 of 替代 in 作为分隔符,因为它更接近 JavaScript 迭代器的语法:
<div v-for="item of items"></div>
v-for 遍历对象
<ul id="v-for-object" class="demo"> <li v-for="(value, name, index) in myObject"> {{ index }}. {{ name }}: {{ value }} </li> </ul>
Vue.createApp({ data() { return { myObject: { title: 'How to do lists in Vue', author: 'Jane Doe', publishedAt: '2016-04-10' } } } }).mount('#v-for-object')
在遍历对象时,会按
Object.keys()
的结果遍历,但是不能保证它在不同 JavaScript 引擎下的结果都一致。
维护状态(重要)
当 Vue 正在更新使用 v-for 渲染的元素列表时,它默认使用“就地更新”的策略。
如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。
这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出。
为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一的 key attribute:
<div v-for="item in items" :key="item.id"> <!-- 内容 --> </div>
建议尽可能在使用 v-for 时提供 key attribute,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。
因为它是 Vue 识别节点的一个通用机制,key 并不仅与 v-for 特别关联。后面我们将在指南中看到,它还具有其它用途。
提示:不要使用对象或数组之类的非基本类型值作为 v-for 的 key。请用字符串或数值类型的值。
Key的更多详解:https://v3.cn.vuejs.org/api/special-attributes.html#key
数组更新检测
1、变更数组的函数
- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
使用上面的函数修改数组,就是局部修改原始数组,即:变更调用了这些方法的原始数组;
2、替换数组的函数
filter()、concat() 和 slice()
它们不会变更原始数组,而总是返回一个新数组。当使用非变更方法时,可以用新数组替换旧数组:
example1.items = example1.items.filter(item => item.message.match(/Foo/))
你可能认为这将导致 Vue 丢弃现有 DOM 并重新渲染整个列表。其事实并非如此。Vue 为了使得 DOM 元素得到最大范围的重用而实现了一些智能的启发式方法,所以用一个含有相同元素的数组去替换原来的数组是非常高效的操作。
显示过滤/排序后的结果
有时,我们想要显示一个数组经过过滤或排序后的版本,而不实际变更或重置原始数据。在这种情况下,可以创建一个计算属性,来返回过滤或排序后的数组。
<li v-for="n in evenNumbers" :key="n">{{ n }}</li>
data() { return { numbers: [ 1, 2, 3, 4, 5 ] } }, computed: { evenNumbers() { return this.numbers.filter(number => number % 2 === 0) } }
在计算属性不适用的情况下 (例如,在嵌套的 v-for 循环中) 你可以使用 方法:
<ul v-for="numbers in sets"> <li v-for="n in even(numbers)" :key="n">{{ n }}</li> </ul>
data() { return { sets: [[ 1, 2, 3, 4, 5 ], [6, 7, 8, 9, 10]] } }, methods: { even(numbers) { return numbers.filter(number => number % 2 === 0) } }
v-for 使用整数
<div id="range" class="demo"> <span v-for="n in 10" :key="n">{{ n }} </span> </div>
在 <template> 中使用 v-for
类似于 v-if,你也可以利用带有 v-for 的 <template> 来循环渲染一段包含多个元素的内容。
<ul> <template v-for="item in items" :key="item.msg"> <li>{{ item.msg }}</li> <li class="divider" role="presentation"></li> </template> </ul>
v-for 与 v-if 一同使用
v-if 的优先级比 v-for 更高
不推荐在一个元素上使用 v-for 和 v-if,这意味着 v-if 将没有权限访问 v-for 里的变量:
<!-- 这将抛出一个错误,因为“todo” property 没有在实例上定义 --> <li v-for="todo in todos" v-if="!todo.isComplete"> {{ todo.name }} </li>
可以把 v-for 移动到 <template> 标签中来修正:
<template v-for="todo in todos" :key="todo.name"> <li v-if="!todo.isComplete"> {{ todo.name }} </li> </template>
在组件上使用 v-for
注意:你需要先学习 组件Component 这节,再来看这里;
点击查看这内容:点我
下一章:事件处理