条件渲染,列表渲染
一、条件渲染
1、v-if,v-else,v-show,v-esle-if(2.1.0后新增)的使用
v-if的使用
<div v-if="isShow">
<h2>title</h2>
<p>detail</p>
</div>
v-else的使用
<div id="app">
<div v-if="isShow">
<h2>title_show</h2>
<p>detail_show</p>
</div>
<div v-else>
<h2>title_hidden</h2>
<p>detail_hidden</p>
</div>
</div>
v-else-if的使用
<div id="app">
<div v-if="count>10">
<h2>title_10</h2>
<p>detail_10</p>
</div>
<div v-else-if="count>0">
<h2>title_0</h2>
<p>detail_0</p>
</div>
<div v-else>
<h2>title_hidden</h2>
<p>detail_hidden</p>
</div>
</div>
v-show的使用
<div id="app">
<div v-show="isOk">
<h2>title_show</h2>
<p>detail_show</p>
</div>
<div v-show="!isOk">
<h2>title_hidden</h2>
<p>detail_hidden</p>
</div>
</div>
2、v-if与v-show的区别
- v-if是通过移除标签来实现隐藏和显示的切换,在切换过程中条件块内的子组件以及监听器会被销毁和重建。
- v-if在初始渲染条件为假时,则不会进行渲染,只有当v-if条件变为真的时候,才开始渲染。且v-if条件变为假的时候,直接销毁。
- v-show,在初始化渲染条件下就会创建,且始终在内存中存在。通过css控制隐藏与现实的切换。
3、 < template >元素上使用v-if条件渲染分组
有时候会出现一组元素标签需要进行v-if进行条件渲染。通常做法是在外面包裹一个div,然后在div上进行v-if处理。当然,vue中也可以使用template标签进行一组元素标签的包裹,在template标签上做v-if处理。渲染处出来的结果不包含template
#template只起到包裹作用,自身不会被渲染到html中。
<template v-if="isOk">
<h2>title_show</h2>
<p>detail_show</p>
</template>
<template v-else>
<h2>title_hidden</h2>
<p>detail_hidden</p>
</template>
4、条件渲染的重用问题(表单元素)
被v-if,v-else-if,v-else包裹的组件或元素,vue会尽可能的复用,使用新的数据去更新旧的dom。这种效率较高的dom使用方式,有时候也会导致一些显示上的问题,主要体现在表单元素上。
重复利用dom下的显示问题情形
#vue虽然会重用input的时候,刷新palceholder,但是不能刷新value,导致切换的时候,显示同样的数据。
#当然,因为vue在重复利用旧的dom时,会尽可能的用新的数据来刷新旧的dom,如果两个input,指定v-model,在切换的时候,也会用v-model对应的变量的数据来刷新旧的dom。
<div id="app">
<button @click="toggle">切换</button>
<div v-if="isLogin">
<h2>登录</h2>
<input placeholder="请输入账号">
</div>
<div v-if="!isLogin">
<h2>注册</h2>
<input placeholder="请输入密码">
</div>
</div>
利用key来避免元素的重复利用
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username" key="username-input">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address" key="email-input">
</template>
二、列表渲染
基于数组的v-for使用
- v-for=“item in list” 只接受value一个参数的形式。
- v-for="(item,index) in list" 接受value,index两个参数的形式。
<div id="app">
<div style="margin-top: 10px; background-color: #eee" v-for="(item, index) in list" :key="index">
<h2>{{item.title}}</h2>
<p>{{item.detail}}</p>
</div>
</div>
基于对象的v-for使用
v-for遍历对象,实际是调用的object.keys(object).forEach(…)形式遍历。
- v-for=“item in object” 只接受value一个参数的形式。
- v-for="(item,key) in object" 接受 value,key两个参数的形式。
- v-for="(item,key, index) in object" 接受value,key,index三个参数的形式。
<div style="margin-top: 10px; background-color: #eee" v-for="(value, key, index) in object" :key="index">
{{ key }} - {{ value }} - {{ index }}
</div>
data: {
object : {
name : 'meng',
age : 24,
gender : '男'
}
}
基于数字的v-for使用
v-for 也可以接受整数。在这种情况下,它会把模板重复对应次数。
<div v-for="item in 10">
{{ item }}
</div>
在< template>
上使用v-for
< template>标签主要用于创建分组,减少外层无意义的div包裹。< template>自身不会被渲染。
<div id="app">
<template v-for="(item,key,idnex) in object">
<p> {{ key }} - {{item}} </p>
</template>
</div>
维护状态
当vue更新使用v-for渲染的元素列表时,默认采用“就地更新”的策略。如果原有列表数据项的位置发生改变,比如插入,删除,排序,过滤等。vue并不会根据改变的数据的位置来修改dom的位置,而是直接用新顺序的数据,更新原有顺序的dom列表。这种刷新方式,如果有临时dom状态,或者依赖子组件状态,且这些状态不能通过新的数据项来更新,那么显示就会出现异常。 比如:
<div id="app">
<button @click="add">新增</button>
<div v-for="(item, index) in list" style="border: 1px solid red; margin-top: 20px">
输如框<input type="text">
<p>{{ item }}</p>
<button @click="remove(index)" >删除</button>
</div>
</div>
<script>
const vm = new Vue({
el : '#app',
data: {
list: [ 'meng', 24, '男' ]
},
methods: {
toggle(){
this.isLogin = ! this.isLogin;
},
remove( index ){
this.list = this.list.filter( function( item, itemIndex ){
return index != itemIndex;
});
},
add(){
this.list.push(this.list.length);
}
}
});
</script>
与v-if切换时,利用旧的dom类似的问题,也可以利用key attribute
来处理。当v-for中的dom项,指定唯一标示key之后,vue就能跟踪每个节点的身份,从而重用和重新排序现有元素。
<div v-for="item in items" v-bind:key="item.id">
...
</div>
数组更新检测
vue只能感知到数组本身的变化,而检测不到数组内部的元素变化。但是vue对数组的一些方法进行了重写,当通过调用以下方法来改变数组元素时,vue能感知到数组内部元素的变化,从而触发视图更新.
-
push()
push() 方法可向数组的末尾添加一个或多个元素,并返回新的长度。#list含有[1,2,3] list.push(4); #list含有[1,2,3,4]
-
pop()
数组从末尾删除一个元素。#list含有[1,2,3] list.pop(); #list含有[1,2]
-
shift()
shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值。#list含有[1,2,3] list.shift(); #list含有[2,3]
-
unshift()
unshift() 方法可向数组的开头添加一个或更多元素,并返回新的长度。#list含有[1,2,3] list.unshift(4,5); #list含有[4,5,1,2,3]
-
splice()
splice() 方法向/从数组中添加/删除项目,然后返回被删除的项目。(该方法改变原始数组)<div id="app"> <button @click="add">增加</button> <button @click="remove">删除</button> <button @click="replace">替换</button> {{ JSON.stringify(list) }} </div> <script> /* * splice()方法 * 第一个参数: index 必须; 整数,规定添加,删除,替换的起始位置. * 第二个参数: howmany 必须; 整数,表示要删除的项目的数量.可以为0. * 第三个参数: item1,...,itemx **/ const vm = new Vue({ el : '#app', data: { list: [1,2,3,4,5] }, methods: { add(){ //指定第二个参数为0,即不删除元素; //指定第二个以后的参数,表示新插入的元素; this.list.splice(3, 0, 10); }, remove(){ //指定删除一个元素,但是不增加新元素. this.list.splice(3,1); }, replace(){ //用新元素替换旧的元素. this.list.splice(3, 1, 10,11); } } }); </script>
-
sort()
sort() 方法用于对数组的元素进行排序。数组在原数组上进行排序,不生成副本。不传参时默认的排序规则是: 按照字符串升序的规则排序。也可以传递一个回调函数,回调函数第一个参数是数组后面的值,第二个参数是前面的值。 比如[1,2,3,4], 第一个参数是2,第二个参数就是1.
- 若a 小于 b,在排序后的数组中 a 应该出现在 b 之前,则返回一个小于0的值。
- 若a 等于 b,则返回0。
- 若a 大于 b,则返回一个大于0的值。
<div id="app"> <button @click="sort">排序</button> {{ JSON.stringify(list) }} </div> <script> const vm = new Vue({ el : '#app', data: { list: [3,2,4,1,5] }, methods: { sort(){ this.list.sort( function( first, last ){ console.log( first, last ) #这里是返回大于0,等于0,小于0的值; #而不是返回true,false的布尔值。 return first - last } ); } } });
-
reverse()
数组检测 和 对象检测 需要注意的问题
1、vue不能检测到利用索引改变数组项的情形
vm.items[index] = 2; 并不会更新视图。
2、vue不能检测到数组长度修改的情形
vm.items.length = 10;
3、在vue模板初始化后,再添加到data下的对象,不会响应式。如果确定需要某个元素,可以现在data中声明一个,初始化为null即可。
关于数组分页,过滤,排序的处理方式
1、第一种方式,定义一个过滤方法,返回一个处理后的数组
#这种方式没有缓存,每次调用都去调用方法,运算出结果。
<li v-for="n in even(numbers)">{{ n }}</li>
data: {
numbers: [ 1, 2, 3, 4, 5 ]
},
methods: {
even: function (numbers) {
return numbers.filter(function (number) {
return number % 2 === 0
})
}
}
2、第二种方式,定义一个计算属性,get方法返回一个处理后的数组
#这种方式利用计算属性的缓存
<li v-for="n in evenNumbers">{{ n }}</li>
data: {
numbers: [ 1, 2, 3, 4, 5 ]
},
computed: {
evenNumbers: function () {
return this.numbers.filter(function (number) {
return number % 2 === 0
})
}
}
v-for 和 v-if 同时作用在一个元素
当他们处于同一个节点,v-for优先级高于v-if, 也就是说 v-for先渲染出列表,然后v-if判断渲染出的列表项是否显示。
-
如果想部分项渲染节点,这种优先级机制十分有用。
<div v-for="item in list" bv-if="item.isSelect"> </div>
-
如果是想有条件的跳过循环的执行。可以使用< template> 或者 外面多包裹一个div,将v-if至于循环的外层元素。
<template v-if="isShow"> <div v-for="item in list">{{item}}</div> </template>