一、v-for用数组
(1)一个参数(html迭代名)
格式: v-for=”item in items”
(item:html迭代名;items:data里的数组名。)
<ul id="app">
<li v-for="item in myarr">
{{item.message}}
</li>
</ul>
<!-- 若用如下html代码,则不会生效。必须用子节点遍历-->
<!--
<ul id="app" v-for="item in myarr">
{{item.message}}
</ul>-->
<script type="text/javascript">
var vm = new Vue({
el:"#app",
data:{
myarr:[
{message:"bty"},
{message:"who"},
{message2:"who2"},
]
}
});
</script>
输出:(message只有两个,但是遍历完却出来3个点,说明myarr是根据数组长度遍历的,而不是单纯根据message的个数遍历)
- bty
- who
若将上面html代码改为如下,也能很好证明上面的说法(js代码不变)
<ul id="app">
<li v-for="item in myarr">
{{item.message2}}
</li>
</ul>
输出:
- who2
(2)两个参数(html迭代名)
格式: v-for=”(item,index) in items”
(index:索引;item:html迭代名;items:data里的数组名。)
将上面html代码改为:
<ul id="app">
<li v-for="(item,index) in myarr">
key-val: {{index}} - {{item.message}}<br>
item: {{item}}<br>
myarr: {{myarr}}
</li>
</ul>
输出:
- key-val: 0 - bty
- item: { “message”: “bty” }
- myarr: [ { “message”: “bty” }, { “message”: “who” } ]
- key-val: 1 - who
- item: { “message”: “who” }
- myarr: [ { “message”: “bty” }, { “message”: “who” } ]
二、v-for用对象
(1)一个参数
格式: v-for=”value in object”
(value:属性值;)
<ul id="app">
<li v-for="value in object">
{{value}}<br>
{{object}}
</li>
</ul>
<!-- 若用如下html代码,则不会生效。必须用子节点遍历-->
<!--
<ul id="app" v-for="value in object">
{{value}}<br>{{object}}
</ul>-->
<script type="text/javascript">
var vm = new Vue({
el:"#app",
data:{
object:{
message:"bty",
message2:"who"
}
}
});
</script>
输出:
- bty
- { “message”: “bty”, “message2”: “who” }
- who
- { “message”: “bty”, “message2”: “who” }
(2)两个参数
格式: v-for=”(value,key) in object”
(value:属性值;key:属性名。)
将上面html代码改为:
<ul id="app">
<li v-for="(value,key) in object">
{{key}} - {{value}}
</li>
</ul>
输出:
- message - bty
- message2 - who
(3)三个参数
格式: v-for=”(value,key,index) in object”
(index:参数索引;value:属性值;key:属性名。)
将上面html代码改为:
<ul id="app">
<li v-for="(value,key,index) in object">
{{index}} - {{key}} - {{value}}
</li>
</ul>
输出:
- 0 - message - bty
- 1 - message2 - who
三、key
建议尽可能在使用 v-for 时提供 key,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。
因为它是 Vue 识别节点的一个通用机制,key 并不与 v-for 特别关联,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" v-bind:key="item.id">
<!-- 内容待研究 -->
</div>
四、数组更新检测
1、变异方法
变异方法 :会改变被这些方法调用的原始数组。
Vue 包含一组观察数组的变异方法,所以它们也将会触发视图更新。这些方法如下:
- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
你打开控制台,然后用前面例子的 items 数组调用变异方法:
vm.myarr.push({ message: ‘Baz’ }) 。
2、非变异方法
非变异方法:不会改变原始数组,但总是返回一个新数组。
当使用非变异方法时,可以用新数组替换旧数组:
- filter() 链接
- concat()
- slice()
vm.items = vm.myarr.filter(function (item) {
return item.message.match(/bty/)
})
你可能认为这将导致 Vue 丢弃现有 DOM 并重新渲染整个列表。幸运的是,事实并非如此。Vue 为了使得 DOM 元素得到最大范围的重用而实现了一些智能的、启发式的方法,所以用一个含有相同元素的数组去替换原来的数组是非常高效的操作。
3、两类问题
由于 JavaScript 的限制,Vue 不能检测如下两类情况的变动的数组:
第一类问题:
<ul id="app">
<li v-for="item in myarr">
{{item.message}}
</li>
</ul>
<script type="text/javascript">
var vm = new Vue({
el:"#app",
data:{
myarr:[
{message:"bty"},
{message:"who"},
]
}
});
vm.myarr[0] = {message:"AA"};
console.log(vm.myarr[0].message); //"AA"
</script>
虽然vm.myarr[0]变了,但仍输出:
- bty
- who
这是由于 JavaScript 的限制,Vue 不能检测以下变动的数组.
为了解决这类问题,有两种解决方法。
//1) Vue.set
Vue.set(vm.myarr, 0, {message:"AA"})
//2)Array.prototype.splice
vm.myarr.splice(0, 1, {message:"AA"})
修改后的js代码:
<script type="text/javascript">
var vm = new Vue({
el:"#app",
data:{
myarr:[
{message:"bty"},
{message:"who"},
]
}
});
Vue.set(vm.myarr, 0, {message:"AA"});
//或vm.myarr.splice(0, 1, {message:"AA"});
</script>
此时输出变为:
- AA
- who
第二类问题:
待研究
原:vm.myarr.length = newLength
升级:
vm.myarr.splice(newLength)
四、对象更改检测
还是由于 JavaScript 的限制,Vue 不能检测对象属性的添加或删除:
对于已经创建的实例,Vue 不能动态添加 根级别 的响应式属性。但是,可以使用 Vue.set(object, key, value) 方法向 嵌套对象 添加响应式属性。
1、一次添加一个属性
<div id="app">
<li v-for = "value in usermess">{{value}}</li>
</div>
<script type="text/javascript">
var vm = new Vue({
el:"#app",
data:{
usermess: {
name: 'Anika',
}
}
});
Vue.set(vm.usermess,'age',22);
<!--若要将上一句改为如下:
vm.usermess.age = 22;
console.log(vm.usermess.age);
则html仍输出:Anika
控制台输出: 22
html并为响应,所以给用上面Vue.set改成响应式-->
</script>
输出:
- Anika
- 22
你还可以使用 vm.$set 实例方法,它只是全局 Vue.set 的别名:
vm.$set(vm.usermess,'age',22);
2、一次添加多个属性
有时你可能需要为已有对象赋予多个新属性,比如使用 Object.assign() 或 _.extend()。在这种情况下,你应该用两个对象的属性创建一个新的对象。所以,如果你想添加新的响应式属性,
你应该这样做:(Object.assign用法参考)
<div id="app">
<li v-for = "value in usermess">{{value}}</li>
</div>
<script type="text/javascript">
var vm = new Vue({
el:"#app",
data:{
usermess: {
name: 'Anika',
}
}
});
vm.usermess = Object.assign({}, vm.usermess, {
age: 22,
favoriteColor: 'Vue Green'
})
</script>
输出:
- Anika
- 22
- Vue Green
五、显示过滤/排序结果
1、用计算属性处理
<div id="app">
<li v-for="n in evenNumbers">{{ n }}</li>
</div>
<script type="text/javascript">
var vm = new Vue({
el:"#app",
data: {
numbers: [ 1, 2, 3, 4, 5 ]
},
computed: {
evenNumbers: function () {
return this.numbers.filter(function (number) {
return number % 2 === 0
})
}
}
});
</script>
如果你不知道filter():请点击这里
输出:
- 2
- 4
2、用 method 方法处理
在计算属性不适用的情况下 (例如,在嵌套 v-for 循环中) 你可以使用一个 method 方法。
<div id="app">
<li v-for="n in even(numbers)">{{ n }}</li>
</div>
<script type="text/javascript">
var vm = new Vue({
el:"#app",
data: {
numbers: [ 1, 2, 3, 4, 5 ]
},
methods: {
even: function (numbers) {
return numbers.filter(function (number) {
return number % 2 === 0;
})
}
}
});
</script>
输出:同上
六、v-for的其他用法
1、一段取值范围的 v-for
v-for 也可以取整数。在这种情况下,它将重复多次模板。
<div id="app">
<li v-for="n in 5">{{ n }}</li>
</div>
<script type="text/javascript">
var vm = new Vue({
el:"#app",
});
</script>
输出:
- 1
- 2
- 3
- 4
- 5
还可以做运算,实现倒序,如下将html代码改为:
<div id="app">
<li v-for="n in 5">{{ 6-n }}</li>
</div>
输出:
- 5
- 4
- 3
- 2
- 1
2、v-for on a < template>
类似于 v-if,你也可以利用带有 v-for 的 < template> 渲染多个元素。
<div id="app">
<template v-for = "item in arr">
<li>{{item.message}}</li>
</template>
</div>
<script type="text/javascript">
var vm = new Vue({
el:"#app",
data:{
arr:[
{message:"aa"},
{message:"bb"}
]
}
});
</script>
输出:
- aa
- bb
3、v-for with v-if
(1)当它们处于同一节点,v-for 的优先级比 v-if 更高,相当于每次for循环都进行一次if判断。
<div id="app">
<li v-for = "value in objperson" v-if = "!value">{{value}}</li>
<script type="text/javascript">
var vm = new Vue({
el:"#app",
data:{
objperson:{
name:"bty",
age:"22",
yanzhi:false
}
}
});
</script>
输出:
- false
(2)如果你想先 if判断 再for循环,可以如下:
<div id="app">
<!-- 如果objperson.name不为空,则遍历该对象;否则打印 “name is empty!”-->
<ul v-if = "objperson.name">
<li v-for = "value in objperson" >{{value}}</li>
</ul>
<p v-else>name is empty!</p>
</div>
<script type="text/javascript">
var vm = new Vue({
el:"#app",
data:{
objperson:{
name:"",
age:"22",
yanzhi:false
}
}
});
</script>
输出:
name is empty!
4、一个组件的 v-for
2.2.0+ 的版本里,当在组件中使用 v-for 时,key 现在是必须的。
任何数据都不会被自动传递到组件里,因为组件有自己独立的作用域。为了把迭代数据传递到组件里,我们要用 props
看下面dome:
<div id="todo-list-example">
<input
v-model="newTodoText"
v-on:keyup.enter="addNewTodo"
placeholder="Add a todo"
>
<ul>
<li
is="todo-item"
v-for="(todo, index) in todos"
v-bind:key="todo.id"
v-bind:title="todo.title"
v-on:remove="todos.splice(index, 1)"
></li>
</ul>
</div>
<script type="text/javascript">
Vue.component('todo-item', {
template: '\
<li>\
{{ title }}\
<button v-on:click="$emit(\'remove\')">X</button>\
</li>\
',
props: ['title']
})
new Vue({
el: '#todo-list-example',
data: {
newTodoText: '',
todos: [
{
id: 1,
title: 'Do the dishes',
},
{
id: 2,
title: 'Take out the trash',
},
{
id: 3,
title: 'Mow the lawn'
}
],
nextTodoId: 4
},
methods: {
addNewTodo: function () {
this.todos.push({
id: this.nextTodoId++,
title: this.newTodoText
})
this.newTodoText = ''
}
}
})
</script>
具体什么样子自己复制代码去尝试。