用v-for把一个数组对应为一个组件元素
我们用v-for指令根据一组数组的选项列表进行渲染。v-for指令需要使用item in items形式的语法:
<ul>
<li v-for="item in items">
{{ item.message }}
</li>
</ul>
var vm = new Vue({
el: '#el',
data: {
items: [
{message: 'foo'},
{message: 'boar'}
]
}
})
在v-for块中,我们拥有对父作用域属性的完全访问权限。v-for还支持一个可选的第二个参数为当前项的索引。
<ul>
<li v-for="(item, index) in items">
{{ item.message }} {{ index }}
</li>
</ul>
var vm = new Vue({
el: '#el',
data: {
items: [
{message: 'foo'},
{message: 'bar'}
]
}
})
也可以用of替代in作为分隔符,因为它是最接近JavaScript迭代器的语法:
<div v-for="item of items"></div>
一个对象的v-for
也可以使用v-for通过对一个对象的属性迭代。
new Vue({
el: '#el',
data: {
object: {
firstName: 'h',
lastName: 'z',
age: 26
}
}
})
<ul id="v-for-object" class="demo">
<li v-for="value on object">
{{ value }}
/li>
</ul>
也可以提供第二个参数为名:
<div v-for="(value, key) in object">
{{ key }} : {{ value }}
</div>
第三个参数为索引:
<div v-for="(value, key, index) in object">
{{index}}. {{key}}: {{value}}
</div>
Key
当Vue使用v-for正在更新已渲染过的元素列表时,它默认就地复用。如果数据项的顺序被改变,Vue将不会移动DOM元素来匹配数据项的顺序,而是简单的复用此处每个元素,并且 确保它在特定索引下显示已被渲染过的每个元素。
这个默认的模式是高效的,但只适用于不依赖子组件状态或零时DOM状态的列表渲染输出。
为了给Vue一个提示,以便追踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一key属性。理想的key值是每项都有唯一id。它的工作方式类似于一个属性,所以你需要用v-bind来绑定动态值:
<div v-for="item in items" :key="item.id">
</div>
建议尽可能在使用v-for时提供key,除非遍历输出的DOM内容非常简单,或者是刻意依赖默认行为以获取性能上提升。
数组更新检测
(1)变异方法
Vue包含一组观察数组的变异方法,所以它们也将会触发视图更新。这些方法如下:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
(2)替换数组
变异方法,是会改变被这些方法调用的原始数组。相比之下也有非变异方法:
filter()
concat()
slice()
这些方法不会改变原始数组,但是总会返回一个新数组。当使用非变异方法时,可以用新数组替换旧数组:
ex.items = ex.items.filter(function(item) {
return item.message.match(/Foo/)
})
你可能认为这将导致Vue丢弃现有DOM并重新渲染整个列表。Vue为了使得DOM得到最大范围的重用而实现了一些智能的、启发式的方法,所以用一个含有相同元素的数组去替换原来的数组是非常高效的操作。
注意事项
由于JavaScript的限制,Vue补鞥呢检测以下变动的数组:
1. 当你用索引直接设置一个项的时候:vm.items[indexOfItem] = newValue
2. 当你修改数组的长度时,例如:vm.items.length = newLenth
举个例子:
var vm = new Vue({
data: {
items: ['a','b','c']
}
})
vm.items[1] = 'x' //不是响应式的
vm.items.length = 2// 不是响应式的
为了解决第一类问题,以下两种方式都可以实现vm.items[i] = newVal相同的效果,同时也会触发响应式更新:
//Vue.set
Vue.set(vm.items, i, newVal)
//Array.prototype.splice
vm.items.splice(i, 1, newVal)
也可以使用vm.$set实例方法,该方法是全局方法Vue.set的一个别名:
vm.$set(vm.items, i, newVal)
为了解决第二类问题,可以使用splice:
vm.items.splice(newLenght)
对象更改检测注意事项
由于JavaScript的限制,Vue不能检测对象属性的添加或删除:
var vm = new Vue({
data: {
a: 1
}
})
//vm.a是响应式的
//vm.b不是响应式的
对于已经创建的实例,Vue不能动态添加根级别的响应式属性,但是可以通过Vue.set(obj,key,value)方法向嵌套对象添加响应式属性。
var vm = new Vue({
data: {
userProfile: {
name: 'Anika'
}
}
})
你可以添加一个新age属性嵌套的userProfile对象:
Vue.set(vm.userProfile, 'age', 27)
还可以使用vm.$set实例方法,它只是全局Vu.set的别名:
vm.$set(vm.userProfile, 'age', 27)
有事可能需要为已有对象赋予多个新属性,所以,如果你想添加新的响应式属性:
vm.userProfile = Object.assign({}, vm.userProfile, {
age: 27,
favoriteColor: 'vue green'
})
显示过滤/排序结果
有时我们想要显示一个数组的过滤或者排序副本,而不是实际改变原始值,我们可以创建返回过滤或排序数组的计算属性:
<li v-for="n in evenNubers">{{ n }}</li>
data: {
number: [1,2,3,4,5]
},
computed: {
evenNubers:function() {
return this.number.reverse()
}
}
在计算属性不适用的情况下,可以使用method方法。
一段取值范围的v-for
v-for也可以取整数。在这种情况下,它将重复多次模板。
<div>
<span v-for="n in 10">{{ n }}</span>
</div>
v-for on a <template>
类似于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 with v-if
当它们处于同一节点,v-for的优先级比v-if更高,这意味着v-if将分别重复运行于每个v-for循环中。当你想仅有的一些项渲染节点时,这种优先级的机制会十分有用:
<li v-for="todo in todos" v-if="!todo.isComplete">
{{ todo }}
</li>
一个组件的v-for
在自定义组件里,你可以像任何普通元素一样用v-for:
<my-component v-for="item in items" :key="item.id"></my-component>
在2.2.0+版本里面。当组件中使用v-for时,key现在是必须的。
然而,任何数据都不会自动传递到组件中,因为组件有自己的独立作用域,为了把迭代数据传递到组件里,我们要用props:
<my-component
v-for="(item, index) in items"
:item="item"
:index="index"
:key="item.id"
></my-component>
不自动将item注入到原组件里的原因是这会使得组件与v-for的运作耦合,明确组件数据的来源能够使组件在其他场合重复使用。