v-for
我们用v-for
指令根据一组数组的选项列表进行渲染。v-for
指令需要以 item in items
形式的特殊语法,items
是源数据数组并且 item
是数组元素迭代的别名。
基本用法
-
{{ item.message }}
var example1 = new Vue({
el: '#example-1',
data: {
items: [
{message: 'foo' },
{message: 'Bar' }
]
}
})
在 v-for
块内部,我们有完全访问父作用域的属性。v-for
还支持一个可选的第二个参数为当前项的索引。
-
{{ parentMessage }} - {{ index }} - {{ item.message }}
var example2 = new Vue({
el: '#example-2',
data: {
parentMessage: 'Parent',
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
})
你也可以用 of
替代 in
作为分隔符, 所以它是最接近JavaScript迭代器的语法
Template v-for
如同 v-if
模板,你也可以用带有 v-for
的 标签来渲染多个元素块。例如:
- {{ item.msg }}
对象迭代 v-for
你也可以用 v-for
通过一个对象的属性来迭代。
-
{{ value }}
new Vue({
el: '#repeat-object',
data: {
object: {
FirstName: 'John',
LastName: 'Doe',
Age: 30
}
}
})
你也可以提供第二个的参数为键名:
{{ key }} : {{ value }}
第三个参数为索引:
{{ index }}. {{ key }} : {{ value }}
当遍历一个对象时,顺序是根据 Object.keys()
可枚举键名排列,不保证和JavaScript引擎实现是一致的。
整数迭代 v-for
v-for
也可以取整数。在这种情况下,它将重复多次模板
{{ n }}
组件 和 v-for
了解组件相关知识,查看 组件 。
在自定义组件里,你可以像任何普通元素一样用 v-for
。
然而他不能自动传递数据到组件里,因为组件有自己独立的作用域。为了传递迭代数据到组件里,我们要用 props
:
不自动注入 item
到组件里是因为这样能让组件紧密耦合 v-for
怎么运作的。在一些情况下,明确了数据的来源让其组件可重复使用。
下面是一个简单的todo list完整的例子:
Vue.component('todo-item', {
template: '\
\
{{ title }}\
\
<\li>\
',
props: ['title']
})
new Vue({
el: '#todo-list-example',
data: {
newTodoText: '',
todos: [
'Do the dishes',
'Take out the trash',
'Mow the lawn'
]
},
methods: {
addNewTodo: function () {
this.todos.push(this.newTodoText)
this.newTodoText = ''
}
}
})
key
当Vue.js用 v-for
正在更新已渲染过的元素列表时,它默认用 “就地复用” 策略。如果数据项的顺序被改变,而不是移动DOM元素来匹配列表的顺序,Vue将简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。这个类似Vue 1.X的 track-by="$index"
。
这个默认的模式是有效的,但是只适合你的列表渲染输出时不依赖子组件状态或临时DOM状态(例如:表单输入框的值)
给Vue一个提示以便它能跟踪每个节点身份,并且因此重新使用和重新排序现有元素,你需要为每项提供一个唯一 key
属性。一个有效的 key
值是每项唯一ID. 这个特殊的属性相当于Vue 1.x的 track-by
,但它像一个变量,所以你需要用 v-bind
来绑定动态值(简洁写法如下)
它建议尽可能用 v-for
时提供一个 key
。除非迭代DOM内容很简单,或者你有意要依赖于对性能提升的默认行为。
因为它是Vue识别节点的通用的机制,key
还具有并不特别依赖于 v-for
的其他用途,我们将在后面的指南中看到其他用途。
数组更新检测
突变方法
Vue包含一组观察数组的改变原数组的方法,所以它们也将会触发视图更新。这些方法如下:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
你打开控制台,然后用前面例子的 items
数组调用突变方法:example1.items.push({ measage: 'Baz' })
重塑数组
突变方法,顾名思义,改变原始数组的称呼。相比之下,也有不改变原组数的方法,例如:filter()
,concat()
,slice()
。这些不会改变原始数组,但总是返回一个新的数组。当用不改变原数组的方法时,你只需替换旧数组用新的:
example1.items = example1.items.filter(function (item) {
return item.message.match(/Foo/)
})
你可你能认为这将导致Vue丢掉现有DOM和重新渲染整个列表。幸运的是,事实并非如此。Vue实现了一些智能化去最大化的重用DOM元素,所以用另外含有重叠对象的数组替换数组是非常高效的操作。
注意事项
由于JavaScript的限制,Vue不能检测以下变动的数组:
- 当你直接设置一个项的索引时, 例如:
vm.items[indexOfItem] = newValue
- 当你修改数组的长度时, 例如:
vm.items.length = newLength
为了避免第一种情况, 以下两种方式将达到像 vm.items[indexOfItem] = newValue
的效果, 同时也将触发状态更新:
// Vue.set
Vue.set(example1.items, indexOfItem, newValue)
// Array.prototype.splice`
example1.items.splice(indexOfItem, 1, newValue)
避免第二种情况, 使用 splice
:
example1.items.splice(newLength)
显示过滤/排序结果
有时我们无需实际改变或重置原始数据对数组进行过滤或排序。在这种情况下,你可以创建计算的属性返回过滤或排序的数组。
例如:
{{ n }}
data: {
numbers: [ 1, 2, 3, 4, 5 ]
},
computed: {
evenNumbers: function () {
return this.numbers.filter(function (number) {
return number % 2 === 0
})
}
}
此外, 你也可以只使用一种方法计算 (例如: 嵌套在 v-for
里循环),但是性能是低效的:
{{ n }}
data: {
numbers: [ 1, 2, 3, 4, 5 ]
},
methods: {
even: function (numbers) {
return numbers.filter(function (number) {
return number % 2 === 0
})
}
}