列表渲染
v-for
用
v-for
指令基于一个数组来渲染一个列表。v-for
指令需要使用item in items
形式的特殊语法,其中items
是源数据数组,而item
则是被迭代的数组元素的别名。
<div id="app">
<ul>
<li v-for="(item, index) in items" :key="index">
{{parent}}-{{index}}-{{item.message}}
</li>
</ul>
</div>
<script>
let vm = new Vue({
el: '#app',
data: function () {
return {
parent: 'Parent',
items: [{ message: 'foo' }, { message: 'bar' }, { message: 'you' }]
}
}
})
</script>
也可以用
of
来代替in
v-for
中使用对象
<div id="app">
<p v-for="(item, name,index) in object" :key="index">
{{index}}.{{name}}:{{item}}
</p>
</div>
<script>
let vm = new Vue({
el: '#app',
data: function () {
return {
object: {
name: 'dabc',
age: 13,
sex: 'boy'
}
}
}
})
</script>
维护状态
当 Vue 正在更新使用
v-for
渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。
只适用于不依赖子组件状态或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出。
为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key
attribute:
<div v-for="item in items" v-bind:key="item.id">
<!-- 内容 -->
</div>
数组更新检测
变更方法
Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。这些被包裹过的方法包括:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
你可以打开控制台,然后对前面例子的 items
数组尝试调用变更方法。比如 example1.items.push({ message: 'Baz' })
。
替换数组
变更方法,顾名思义,会变更调用了这些方法的原始数组。相比之下,也有非变更方法,例如 filter()
、concat()
和 slice()
。它们不会变更原始数组,而总是返回一个新数组。当使用非变更方法时,可以用新数组替换旧数组:
example1.items = example1.items.filter(function (item) {
return item.message.match(/Foo/)
})
你可能认为这将导致 Vue 丢弃现有 DOM 并重新渲染整个列表。幸运的是,事实并非如此。Vue 为了使得 DOM 元素得到最大范围的重用而实现了一些智能的启发式方法,所以用一个含有相同元素的数组去替换原来的数组是非常高效的操作。
注意事项
由于 JavaScript 的限制,Vue 不能检测数组和对象的变化。
显示过滤/排序后的结果
有两种方法实现:计算属性和嵌套v-for
的methods方法
计算属性
<div id="app">
<li v-for="(item, index) in evenNumbers" :key="index">
{{item}}
</li>
</div>
<script>
let vm = new Vue({
el: '#app',
data: function () {
return {
numbers: [1, 2, 3, 4, 5]
}
},
computed: {
evenNumbers: function () {
return this.numbers.filter(function (number) {
return number % 2 === 0
})
}
}
})
</script>
methods方法
<div id="app">
<ul v-for="(set, index) in numbers" :key="index">
<li v-for="(n, index) in evenNumber(set)" :key="index">{{n}}</li>
</ul>
</div>
<script>
let vm = new Vue({
el: '#app',
data: function () {
return {
numbers: [[1, 2, 3, 4, 5]]
}
},
methods: {
evenNumber: function (numbers) {
return numbers.filter(function (number) {
return number % 2 === 0
})
}
}
})
</script>
在v-for
中使用值范围
<div>
<span v-for="n in 10">{{ n }} </span>
</div>
结果为:12345678910
在<template>
上使用v-for
类似于v-if
<div id="app">
<template v-for="(item, index) in items" :key="index">
<h1>{{item.message}}</h1>
<h2>我是分隔线</h2>
<hr />
</template>
</div>
<script>
let vm = new Vue({
el: '#app',
data: function () {
return {
items: [{ message: 'foo' }, { message: 'bar' }, { message: 'you' }]
}
}
})
</script>
v-for
与v-if
注意我们不推荐在同一元素上使用
v-if
和v-for
- 当它们处于同一节点,
v-for
的优先级比v-if
更高,这意味着v-if
将分别重复运行于每个v-for
循环中。当你只想为部分项渲染节点时,这种优先级的机制会十分有用
<div id="app">
<table border="1" cellspacing="0">
<tr
v-for="(item, index) in items"
:key="index"
v-if="item.sex==='girl'"
>
<td>{{item.name}}</td>
<td>{{item.age}}</td>
<td>{{item.sex}}</td>
</tr>
</table>
</div>
<script>
let vm = new Vue({
el: '#app',
data: function () {
return {
items: {
alice: {
name: 'alice',
age: 13,
sex: 'girl'
},
bob: {
name: 'bob',
age: 14,
sex: 'boy'
},
mary: {
name: 'mary',
age: 15,
sex: 'girl'
}
}
}
}
})
</script>