Vue.js v-for
v-for
- 预期:
Array | Object | number | string | Iterable (2.6 新增)
用法
基于源数据多次渲染元素或模板块。此指令之值,必须使用特定语法 alias in expression
,为当前遍历的元素提供别名:
<div v-for="item in items">
{{ item.text }}
</div>
另外也可以为数组索引指定别名 (或者用于对象的键):
<div v-for="(item, index) in items"></div>
<div v-for="(val, key) in object"></div>
<div v-for="(val, name, index) in object"></div>
v-for
的默认行为会尝试原地修改元素而不是移动它们。要强制其重新排序元素,你需要用特殊属性 key
来提供一个排序提示:
如果该数组可能是会变化的,不要使用 index 作为 key,可以使用固定的某个值,比如user_id
<div v-for="item in items" :key="item.id">
{{ item.text }}
</div>
数组中使用 v-for
<div id="app">
<ul>
<li v-for="(item, index) in list">
index: ${ index }, name: ${ item.name }
</li>
</ul>
</div>
var vm = new Vue({
el: '#app',
delimiters: ['${', '}'],
data: {
list: [
{ id: '123456789', name: ' 1111' },
{ id: '234567890', name: ' 2222' },
{ id: '345678901', name: ' 3333' },
],
},
});
对象中使用 v-for
<div id="app">
<ul>
<li v-for="(item, key, index) in list">
index: ${ index }, key: ${ key }, name: ${ item.name }
</li>
</ul>
</div>
var vm = new Vue({
el: '#app',
delimiters: ['${', '}'],
data: {
list: {
'123456789': { name: '選項 1' },
'234567890': { name: '選項 2' },
'345678901': { name: '選項 3' },
},
},
});
在迭代中使用 v-for
div>
<span v-for="n in 10">${ n }</span>
</div>
<template
标签
<div id="app">
<ul>
<template v-for="(item, index) in list">
<li>index: ${ index }, name: ${ item.name }</li>
</template>
</ul>
</div>
其他
从 2.6 起,v-for
也可以在实现了可迭代协议的值上使用,包括原生的 Map
和 Set
。不过应该注意的是 Vue 2.x 目前并不支持可响应的 Map
和 Set
值,所以无法自动探测变更。
当和 v-if
一起使用时,v-for
的优先级比 v-if
更高。详见列表渲染教程
v-for
的详细用法可以通过以下链接查看教程详细说明。
参考
Key 说明
由于效能考虑,在默认的状况下,Vue.js 会尽量重复使用已渲染好的元素。
若不设定 key 值,不会重新渲染元素,只会部份更新。
不使用 Key 的演示
<div id="app">
<ul>
<li v-for="(item, index) in list">${ index } <input type="text" :placeholder="item.name" /></li>
</ul>
</div>
var vm = new Vue({
el: '#app',
delimiters: ['${', '}'],
data: {
list: [
{ id: '123456789', name: '選項 1' },
{ id: '234567890', name: '選項 2' },
{ id: '345678901', name: '選項 3' },
],
},
});
初始画面,用户分别在每个输入框中输入文字。
使用改变元素顺序后,虽然元素被更新,但用户的输入被保留,这是因为元素并没有被重新渲染,而只是部份更新而已。vm.list.reverse()
使用 Key
修改上例,每个 都使用 绑定一个属性 并设定唯一值,目的是确保每个元素的唯一性,
当元素更新,例如改变顺序时,有可识别唯一性的 key 来确保重新渲染。<li>v-bind:key
<div id="app">
<ul>
<li v-for="(item, index) in list" :key="item.id">
${ index } <input type="text" :placeholder="item.name" />
</li>
</ul>
</div>
var vm = new Vue({
el: '#app',
delimiters: ['${', '}'],
data: {
list: [
{ id: '123456789', name: '選項 1' },
{ id: '234567890', name: '選項 2' },
{ id: '345678901', name: '選項 3' },
],
},
});
按照不更新的那种更改顺序,设定 key 值便会重新更新;
所有会更改数组的方法
下面这些方法是会更改数组的,需要记住
'push', 新增元素。
'pop', 删除最后一个
'shift', 删除第一个 (即最旧的) 元素。
'unshift',加入元素至第一个位置。
'splice', 加入或移除元素。
'sort', 由小至大排序。
'reverse' 元素反序排列
显示处理后的结果
v-for 迭代的数据是使用 computed
或 methods
处理后的结果。 (不是直接的 Data 数据)
例如:显示数量大于 6 的水果。
<div id="app">
<ul>
<li v-for="item in filteredFrouts">${ item.name }</li>
</ul>
</div>
var vm = new Vue({
el: '#app',
delimiters: ['${', '}'],
data: {
frouts: [
{
name: 'Apple',
count: 10,
},
{
name: 'Orange',
count: 5,
},
{
name: 'Banana',
count: 20,
},
],
},
computed: {
filteredFrouts: function() {
return this.frouts.filter(function(item) {
return item.count > 6;
});
},
},
});
v-for 与 v-if 优先权的比较
v-for
的优先权高于v-if
,因此当两者皆出现在同一个元素上时,v-if
会随着v-for
重覆执行数次。
如下所示,v-if
会执行 10 次,每次都会判断 n 除以 2 的余数是否为 1,若为 1 则显示,否则就隐藏。
<ul>
<li v-if="n % 2 === 1" v-for="n in 10">${ n }</li>
</ul>
注意,v-for 的个数范围判断条件成立后,才会轮到 v-if 来判断显示与否。
这是什么意思呢?来看下一个例子就知道了。
如下所示,这里同时出现了 v-for、v-if 和 v-else 三个指令。
在这个例子中,我们试图印出 list 阵列的元素内容,而目前 list 是空阵列,没有任何项目可显示。
因此,当 v-for 在判断 item in list 时,发现条件不成立,就不去做 v-if 和 v-else 判断了,导致原本没有元素印出时应该要提示的「Nothing could show.」
都没有出现:(
<div id="app">
<div v-if="list.length !== 0" v-for="item in list">
<div>${ item.name }</div>
</div>
<div v-else>
Nothing could show.
</div>
</div>
new Vue({
el: '#app',
delimiters: ['${', '}'],
data: {
list: [],
},
});
总结,由于 v-for 优先权较高,当 v-for 执行完条件判断后,若条件不成立,则后面的 v-if 也不会执行,接着忽略了其后的 v-else。
解决办法
解法如下,让 v-for 来判断 list 是否有内容的状况,v-if 只要负责处理项目为 0 个的情况即可。
<div id="app">
<div v-for="item in list">
<div>${ item.name }</div>
</div>
<div v-if="list.length === 0">
Nothing could show.
</div>
</div>
参考:https://cythilya.github.io/2017/04/27/vue-list-rendering/