列表渲染适合于一些复用性比较高的元素
关键词:v-for指令
有序列表ol和无序列表ul是天然可以适用这种情况的元素。
如下例子
<ul id="vm1">
<li v-for="item in items" :key="item.message">
{{ item.message }}
</li>
</ul>
<script>
var vm1 = new Vue({
el: '#vm1',
data: {
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
})
</script>
运行结果如图:
重复化渲染
我们可以看到,应用v-for,使用一个类似于循环的操作,遍历items中所有的对象,取出message值,这种复用可以减少html复杂而又几乎同质化的元素操作。
当然,v-for指令还提供了index这个隐藏参数。
我们可以使用index来确定元素在“数组”中的序列。
<!-- 大胆猜测一下,内部实现可能是一个jsx语法的each迭代器 -->
<ul id="vm2">
<li v-for="(item, index) in items">
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
</ul>
<script type="text/javascript">
var vm2 = new Vue({
el: '#vm2',
data:{
parentMessage: 'Parent',
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
})
</script>
如图所示~
当然,v-for也可以用来遍历对象中的属性。
<ul id="vm3">
<li v-for="value in object">
{{ value }}
</li>
</ul>
<script type="text/javascript">
var vm3 = new Vue({
el: '#vm3',
data: {
object: {
title: 'Get subscribe and Hit the like button',
author: 'Luohuatingyu',
publishedAt: '2020-05-12'
}
}
})
</script>
内部类似于原生js中的for-in循环
与此同时,键名作为一个可选参数,也可以出现在参数列表里。
<!-- 官方解释是用Object.keys()遍历,由于各个浏览器使用的引擎不一致,所以会有些许差异 -->
<ul id="vm3_1">
<li v-for="(value, name, index) in object">
No{{ index }}: "{{ name }}" : "{{ value }}"
</li>
</ul>
<script type="text/javascript">
var vm3_1 = new Vue({
el: '#vm3_1',
data: {
object: {
title: 'Get subscribe and Hit the like button',
author: 'Luohuatingyu',
publishedAt: '2020-05-12'
}
}
})
</script>
结果显而易见
简单拼接
在开始下面的介绍之前,先介绍一下JavaScript数组中的两类方法
- 变异方法
pop()
shift()
unshift()
splice()
sort()
reverse()
- 非变异方法
filter()
slice()
...
显而易见,所有的变异方法都是对原数组进行修改的方法,而非变异方法反之,会得到一个新数组。
在Vue中,变异方法的调用,也会触发视图的更新操作。
这为我们提供了一个新思路,如果说,你的项目中不想对原数组进行修改,可以使用计算属性,每次获取一个原数组的拷贝。
<!-- 使用计算属性(不改变原数组) -->
<ul id="vm4">
<li v-for="n in evenNumbers">{{ n }}</li>
</ul>
<script type="text/javascript">
var vm4 = new Vue({
el: '#vm4',
data: {
numbers: [ 1, 2, 3, 4, 5 ]
},
computed: {
evenNumbers: function () {
return this.numbers.filter(function (number) {
return number % 2 === 0
})
}
}
})
</script>
结果就像这样
计算属性
当然对于计算属性来说,多重循环是不适用的,这里我们可以用Vue中提供的方法。
<!-- 可以使用even方法来应用于计算属性不适用的情况(例如多重循环) -->
<div id="vm5">
<ul v-for="set in sets">
<li v-for="n in even(set)">{{ n }}</li>
</ul>
</div>
<script type="text/javascript">
var vm5 = new Vue({
el: '#vm5',
data: {
sets: [[ 1, 2, 3, 4, 5 ], [6, 7, 8, 9, 10]]
},
methods: {
even: function (numbers) {
return numbers.filter(function (number) {
return number % 2 === 0
})
}
}
})
</script>
这样就会有两个ul被渲染出来,对应两个子数组。
计算属性不适用的情况
既然v-for号称循环指令,最基本的计数循环也可以做。
<!-- 使用整数来限制循环次数也是可以的 -->
<div id="vm6">
<span v-for="n in 10">{{ n }} </span>
</div>
<script type="text/javascript">
var vm6 = new Vue({
el: "#vm6"
})
</script>
打印一组数字
也可以结合template,渲染一组元素。
<!-- 也可以使用template渲染一组元素 -->
<ul id="vm7">
<template v-for="item in items">
<li>{{ item.msg }}</li>
<li class="divider" role="presentation"></li>
</template>
</ul>
<style>
.divider{
opacity: 0;
height: 2em;
list-style: none;
}
</style>
<script type="text/javascript">
var vm7 = new Vue({
el: '#vm7',
data: {
items: [
{ msg: "Hello" },
{ msg: "Thank you" },
{ msg: "Thank you very much" },
{ msg: "How are you" },
{ msg: "I am fine" }
]
}
})
</script>
效果图如下,中间的空行用来格式控制,但是它们是实际存在的元素。
格式控制有人会问了,那v-if和v-for有什么关系吗?
在官方的文档中,不建议同时使用。
如果使用了,优先级如下。
<!-- 这个示例告诉我们,如果v-for和v-if出现在同一个标记上,那么先执行v-for,然后在v-if里进行判断是否渲染循环中的元素 -->
<ul id="vm8">
<li v-for="todo in todos" v-if="!todo.isComplete">
{{ todo.title }} : {{ todo.content }}
</li>
</ul>
<script type="text/javascript">
var vm8 = new Vue({
el: '#vm8',
data: {
todos: [
{
title: "Work",
content: "Coding web page with Vue",
isComplete: false
},
{
title: "Sleep",
content: "Having a nice sleep",
isComplete: true
},
{
title: "Learning",
content: "Learning the new abilitily of Vue",
isComplete: false
}
]
}
})
</script>
v-for和v-if
可以看到,在每一次循环进行之后,才会进行v-if的判断,要不要渲染这个元素。即v-for的优先级大于v-if
如果你想做到按条件决定是否循环,请将v-if中的元素包裹在需要判断是否循环的元素外面。
<ul v-if="todos.length">
<li v-for="todo in todos">
{{ todo }}
</li>
</ul>
<p v-else>No todos left!</p>
最后,又到了Vue关于原理的一部分,我也不太理解,贴点伪码。
<!-- key是Vue中唯一标识一个元素的标记,提供这个标记使得Vue可以跟踪每一个子元素的状态。 -->
<!-- 默认是就地渲染的,即更新子组件的值,并不修改组件,但是如果对子组件有依赖就很麻烦(比如其中的data-*域) -->
<!-- 加key可以避免这一问题(目前我还没遇到) -->
<div v-for="item in items" v-bind:key="item.id">
<!-- 内容 -->
</div>
网友评论