赞
踩
v-for
指令需要使用 item in items
形式的特殊语法,其中 items
是源数据数组,而 item
则是被迭代的数组元素的别名。
v-for
还支持一个可选的第二个参数,即当前项的索引。
在 v-for
块中,我们可以访问所有父作用域的属性。
也可以用 of
替代 in
作为分隔符,因为它更接近 JavaScript 迭代器的语法:
<div>
<li v-for="(item, index) in list" :key="item.id">
<span>{{ index }}--{{ item.name }}</span> // 可以访问父作用域的属性;
</li>
</div>
data () {
return {
list: [
{name: '网易', id: '0'},
{name: '腾讯', id: '1'},
{name: '谷歌', id: '2'}
]
}
}
<div v-for="item of items"></div>
也可以用 v-for
来遍历一个对象。
还提供第二个的可选参数为属性名称 (也就是键名)。
还提供了第三个可选参数作为索引。
注:在遍历对象时,会按 Object.keys()
的结果遍历,但是不能保证它的结果在不同的 JavaScript 引擎下都一致。
<div>
<li v-for="value,key,index in listObj" :key="index">
<span>{{ index }}--{{ key }}--{{ value }}</span>
</li>
</div>
data () {
return {
listObj: {
name: '大黄',
age: 18,
weight: 60
}
}
}
当 Vue 更新使用 v-for
渲染的元素列表时,它默认使用“就地更新”的策略。
如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。
这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出。(换言之对于更改数组顺序或者有输入类表单的时候不适用)
为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key属性
:
<div v-for="item in items" v-bind:key="item.id">
{{ item.name }}
</div>
建议尽可能在使用 v-for
时,提供一个唯一不重复的 key属性
,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。
因为它是 Vue 识别节点的一个通用机制,key
并不仅与 v-for
特别关联。后面我们将在指南中看到,它还具有其它用途。也可查看条件渲染部分对key的解释;
注:不要使用对象或数组之类的非基本类型值作为 v-for
的 key
。请用字符串或数值类型的值。
更多 key
attribute 的细节用法请移步至 key 的 API 文档。
(1)变更方法
Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。
变更方法,顾名思义,会变更调用了这些方法的原始数组。
push(),pop(),shift(),unshift(),splice(),sort(),reverse()
(2)替换数组
以下方法均不不会变更原始数组,而总是返回一个新数组。
当使用非变更方法时,可以用新数组替换旧数组。filter,concat,slice
Vue 并不是丢弃现有 DOM 重新渲染整个列表。Vue 为了使得 DOM 元素得到最大范围的重用而实现了一些智能的启发式方法,所以用一个含有相同元素的数组去替换原来的数组是非常高效的操作。
(3)注意事项
由于 JavaScript 的限制,Vue 不能检测数组和对象的变化。深入响应式原理中有相关的讨论。
有时,我们想要显示一个数组经过过滤或排序后的版本,而不实际变更或重置原始数据。在这种情况下,可以创建一个计算属性,来返回过滤或排序后的数组。
<li v-for="n in evenNumbers">{{ n }}</li>
data: {
numbers: [ 1, 2, 3, 4, 5 ]
},
computed: {
evenNumbers: function () {
return this.numbers.filter(function (number) {
return number % 2 === 0
})
}
}
在计算属性不适用的情况下 (例如,在嵌套 v-for
循环中) 你可以使用一个方法:
<ul v-for="set in sets">
<li v-for="n in even(set)">{{ n }}</li>
</ul>
data: {
sets: [[ 1, 2, 3, 4, 5 ], [6, 7, 8, 9, 10]]
},
methods: {
even: function (numbers) {
return numbers.filter(function (number) {
return number % 2 === 0
})
}
}
v-for
也可以接受整数。在这种情况下,它会把模板重复对应次数。
<div>
<span v-for="n in 10">{{ n }} </span>
</div>
结果是:1 2 3 4 5 6 7 8 9 10
类似于 v-if
,你也可以利用带有 v-for
的 <template>
来循环渲染一段包含多个元素的内容。比如:
<ul>
<template v-for="item in items">
<li>{{ item.msg }}</li>
<li class="divider" role="presentation"></li>
</template>
</ul>
在自定义组件上,你可以像在任何普通元素上一样使用 v-for
。
2.2.0+ 的版本里,当在组件上使用 v-for
时,key
现在是必须的。
<my-component v-for="item in items" :key="item.id"></my-component>
任何数据都不会被自动传递到组件里,因为组件有自己独立的作用域。为了把迭代数据传递到组件里,我们要使用 prop(与普通父子组件传值方法相同)。
不自动将 item
注入到组件里的原因是,如果直接注入会使得组件与 v-for
的运作紧密耦合。而明确组件数据的来源能够使组件在其他场合重复使用。
<my-component
v-for="(item, index) in items"
v-bind:item="item"
v-bind:index="index"
v-bind:key="item.id"
></my-component>
下面是一个简单的 todo 列表的完整例子:
注意这里的 is="todo-item"属性
。这种做法在使用 DOM 模板时是十分必要的,因为在 <ul>
元素内只有 <li>
元素会被看作有效内容。这样做实现的效果与 <todo-item>组件
相同,但是可以避开一些潜在的浏览器解析错误。查看 DOM 模板解析说明 来了解更多信息。
- <div id="todo-list-example">
- <form v-on:submit.prevent="addNewTodo">
- <label for="new-todo">Add a todo</label>
- <input
- v-model="newTodoText"
- id="new-todo"
- placeholder="E.g. Feed the cat"
- >
- <button>Add</button>
- </form>
- <ul>
- <li
- is="todo-item"
- v-for="(todo, index) in todos"
- v-bind:key="todo.id"
- v-bind:title="todo.title"
- v-on:remove="todos.splice(index, 1)"
- ></li>
- </ul>
- </div>
- Vue.component('todo-item', {
- template: '\
- <li>\
- {{ title }}\
- <button v-on:click="$emit(\'remove\')">Remove</button>\
- </li>\
- ',
- props: ['title']
- })
-
- new Vue({
- el: '#todo-list-example',
- data: {
- newTodoText: '',
- todos: [
- {
- id: 1,
- title: 'Do the dishes',
- },
- {
- id: 2,
- title: 'Take out the trash',
- },
- {
- id: 3,
- title: 'Mow the lawn'
- }
- ],
- nextTodoId: 4
- },
- methods: {
- addNewTodo: function () {
- this.todos.push({
- id: this.nextTodoId++,
- title: this.newTodoText
- })
- this.newTodoText = ''
- }
- }
- })
注意我们不推荐在同一元素上使用 v-if
和 v-for
。
当它们处于同一节点,v-for
的优先级比 v-if
更高,这意味着 v-if
将分别重复运行于每个 v-for
循环中,每循环一次就会v-if判断一次当前循环。当你只想为部分项渲染节点时,这种优先级的机制会十分有用,如下。
<li v-for="todo in todos" v-if="!todo.isComplete">
{{ todo }}
</li>// 上面的代码将只渲染符合判断你条件的 todo。
而如果你的目的是有条件地跳过整个循环的执行,那么可以将 v-if
置于外层元素 (或 <template>) 上。如:
<ul v-if="todos.length">
<li v-for="todo in todos">
{{ todo }}
</li>
</ul>
<p v-else>No todos left!</p>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。