Vue3 07.内置指令5 列表渲染
v-for
可以使用v-for
指令基于一个数组来渲染一个列表。v-for
指令的值需要使用item in items
形式的特殊语法,其中items
是源数据的数组,item
是迭代项的别名:
const items = ref([{message: 'Foo'}, {message: 'Bar'}]) |
<li v-for="item in items"> |
在v-for
块中可以完整地访问父作用域内的属性和变量。v-for
也支持使用可选的第二个参数表示当前项的位置索引。
const parentMessage = ref('Parent') |
<li v-for="(item, index) in items"> |
也可以在定义v-for
的变量别名时使用解构和解构函数参数类似:
<li v-for="{message} in items"> |
对于多层嵌套的v-for
,作用域的工作方式和函数的作用域很类似。每个v-for
作用域都可以访问到父级作用域:
<li v-for="item in items"> |
可以使用of
作为分隔符来替代in
:
<div v-for="item of items"></div> |
v-for
与对象
也可以使用v-for
来遍历一个对象的所有属性。遍历的顺序会基于对该对象调用Object.values()
的返回值来决定。
const myObject = reactive({ |
<ul> |
可以通过提供第二个参数表示属性名:
<li v-for="(value, key) in myObject"> |
第三个参数表示位置索引:
<li v-for="(value, key, index) in myObject"> |
在v-for
里使用范围值
v-for
可以直接接受一个整数值。在这种用例中,会将该模板基于1...n
的取值范围重复多次。
<span v-for="n in 10">{{ n }}</span> |
注意此处
n
的初值是从1
开始,而非0
。
<template>
上的v-for
与模板上的v-if
类似,可以在<template>
标签上使用v-for
来渲染一个包含多个元素的块。
<ul> |
通过Key管理状态
Vue默认按照“就地更新”的策略来更新通过v-for
渲染的元素列表。当数据项的顺序改变时,Vue不会随之移动DOM元素的顺序,而是就地更新每个元素,确保它们在原本指定的索引位置上渲染。
默认模式是高效的,但只适用于列表渲染输出的结果不依赖子组件状态或者临时DOM状态的情况。
为了给Vue一个提示,以便它可以跟踪每个节点的标识,从而重用和重新排序现有的元素,你需要为每个元素对应的块提供一个唯一的key
attribute:
<div v-for="item in items" :key="item.id"> |
当你使用<template v-for>
时,key
应该被放置在这个<template>
容器上:
<template v-for="todo in todos" :key="todo.name"> |
推荐在任何可行的时候为v-for
提供一个key
attribute,除非所迭代的DOM内容非常简单。
key
绑定的值期望是一个基础类型的值,例如字符串或Number类型。不要用对象作为v-for
的Key。
组件上使用v-for
可以直接在组件上使用v-for
,和在一般的元素上使用没有区别。
<my-component v-for="item in items" :key="item.id" /> |
但是这不会自动将任何数据传递给组件,因为组件有自己独立的作用域。为了将迭代后的数据传递到组件中,需要传递props:
<my-component |
不自动将item
注入组件的原因是,这会使组件与v-for
的工作方式紧密耦合。明确其数据的来源可以使组件在其他情况下重用。
数组变更检测
Vue能监听响应式数组的变更方法,并在它们被调用时触发相关的更新。
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
还有一些方法会替换数组,比如filter()
,concat()
和slice()
这些都不会更改原数组,而是返回一个新数组。
item.value = items.value.filter((item) => item.message.match(/Foo/)) |
可能会以为这将导致Vue丢弃现有的DOM并重新渲染整个列表,但幸运的是Vue实现了一些巧妙的方法来最大化对DOM元素的重用,所以用另一个数组来做替换,依旧是一种非常高效的操作。