本节的重点内容是v-for指令。
v-for指令将根据指令后的数据,循环的对DOM元素进行渲染。
基础
基础栗子:
<ul id="example-1">
<li v-for="item in items">
{{ item.message }}
</li>
</ul>
var example1 = new Vue({
el: '#example-1',
data: {
items: [
{message: 'Foo' },
{message: 'Bar' }
]
}
})
v-for指令中的双参数与作用域
<ul id="example-2">
<li v-for="(item, index) in items">
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
</ul>
var example2 = new Vue({
el: '#example-2',
data: {
parentMessage: 'Parent',
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
})
结果:
Parent - 0 - Foo
Parent - 1 - Bar
上面的栗子说明:
1、指令中,拥有对父级作用域的完全访问权。
2、可以使用v-for="(item, index) in items"
这样的形式取得当前元素item的index索引。
上面的栗子的循环对象是数组,我们还可以使用in运算符来循环对象的属性:
<ul id="repeat-object" class="demo">
<li v-for="value in object">
{{ value }}
</li>
</ul>
<!-- or -->
<div v-for="(value, key) in object">
{{ key }} : {{ value }}
</div>
<!-- even -->
<div v-for="(value, key, index) in object">
{{ index }}. {{ key }} : {{ value }}
</div>
new Vue({
el: '#repeat-object',
data: {
object: {
firstName: 'John',
lastName: 'Doe',
age: 30
}
}
})
除了循环对象、数组,v-for指令还支持循环数字:
<div>
<span v-for="n in 10">{{ n }}</span>
</div>
输出:1 2 3 4 5 6 7 8 9 10
v-for & v-if
上一节我们已经介绍过,当v-for & v-if共存于同一节点上时,v-for具有比v-if更高的优先级。这意味着,v-if在每次循环迭代上都会运行。
复用策略和key
当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用 “就地复用” 策略。如果数据项的顺序被改变,Vue将不是移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。
这个默认的模式是有效的,但是只适用于不依赖子组件状态或临时 DOM 状态(例如:表单输入值)的列表渲染输出。
为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key 属性。理想的 key 值是每项都有唯一 id。这个特殊的属性相当于 Vue 1.x 的 track-by ,但它的工作方式类似于一个属性,所以你需要用 v-bind 来绑定动态值(在这里使用简写):
<div v-for="item in items" :key="item.id">
<!-- 内容 -->
</div>
建议尽可能使用 v-for 来提供 key ,除非迭代 DOM 内容足够简单,或者你是故意要依赖于默认行为来获得性能提升。
数组更新检测
由于使用v-for时,循环的数据大多是数组,这里我们就引入一些数组的方法。这些方法的执行会触发视图更新:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
上面这些方法都会改变原始数组,因此称为变异方法。
另外,方法 filter(), concat(), slice() 。这些不会改变原始数组,但总是返回一个新数组。这些方法称为非变异方法。当使用非变异方法时,可以用新数组替换旧数组。
例如:
example1.items = example1.items.filter(function (item) {
return item.message.match(/Foo/)
})
当做了数组的替换时,你可能认为这将导致 Vue 丢弃现有 DOM 并重新渲染整个列表。幸运的是,事实并非如此。 Vue 实现了一些智能启发式方法来最大化 DOM 元素重用,所以用一个含有相同元素的数组去替换原来的数组是非常高效的操作。
注意:
vm.items[indexOfItem] = newValue
和vm.items.length = newLength
这两种数组变动,不会触发更新。
我们应该将vm.items[indexOfItem] = newValue改为:
// Vue.set
Vue.set(example1.items, indexOfItem, newValue)