vue2.x之条件渲染和列表渲染
条件渲染
条件渲染,顾名思义,就是根据特定条件渲染内容。在使用条件渲染的时候,我们一般都会使用到两类指令:v-if和v-show
v-if指令
v-if指令的意思就是说当指令的表示式返回的是true,那么就会加载渲染对应的DOM节点,否则就不会加载渲染。
⏰ 基本用法
<div v-if="1 === 1">条件渲染-内容</div>
上面的v-if的表达式返回的是true,所以就会渲染出来。 效果如下:
如果上面那个表达式返回的是false, 那么就不会渲染出来。
<div v-if="1 === 2">条件渲染-内容</div>
效果如下:
⏰ 多个v-if可以同时使用
v-if可以定义多个,只要条件满足,都可以渲染出来。
<div v-if="1 === 1">条件渲染-内容1</div> <div v-if="1 === 2">条件渲染-内容2</div> <div v-if="1 === 1">条件渲染-内容3</div>
效果如下:
条件为true才会加载对应节点,否则不会加载对应节点 效果如下:
内容2的条件返回的是false,那么只有它不会渲染出来
⏰ 搭配v-else-if, v-else使用
这些指令其实和js中的if -> else-if -> else 是一样的。
<div v-if="1 === 2">条件渲染-内容1</div> <div v-else-if="1 === 1">条件渲染-内容2</div> <div v-else-if="1 === 3">条件渲染-内容3</div> <div v-else>条件渲染-内容4</div>
效果如下:
在搭配这些指令使用的时候不能中断,否则后面的内容是不能加载出来的。
div v-if="1 === 2">条件渲染-内容1</div> <div>中断文本</div> <div v-else-if="1 === 1">条件渲染-内容2</div> <div v-else-if="1 === 3">条件渲染-内容3</div> <div v-else>条件渲染-内容4</div>
如果v-if,v-else-if这些指令中途中断了,编辑器就会提示错误,页面不能渲染。
⏰ 搭配template使用
我们之前学习tempplate的标签的时候,就知道它的作用主要就是充当一个容器元素,和普通的容器元素(比如div)相比,它不会渲染成真正的DOM节点。
<template v-if="1 === 1"> <div>条件渲染-内容1</div> <div>条件渲染-内容2</div> <div>条件渲染-内容3</div> <div>条件渲染-内容4</div> </template>
页面渲染的时候没有渲染出tempalate元素,效果如下:
v-show指令
v-show翻译过来就是显示的意思,也就是无论条件是怎样的,这些DOM节点都会加载,如果返回条件是true的话那就显示出来,相当于是display: inline-block或者display: block,否则就是display:none.
⏰ 基本用法
<div v-show="1 === 2">条件渲染-内容1</div> <div v-show="1 === 1">条件渲染-内容2</div>
效果如下:
⏰ 多个v-show同时使用
多个v-show和多个v-if一样,也可以使用多个。
<div v-show="1 === 2">条件渲染-内容1</div> <div v-show="1 === 1">条件渲染-内容2</div> <div v-show="1 === 1">条件渲染-内容3</div> <div v-show="1 === 1">条件渲染-内容4</div>
效果如下:
v-if和v-show的区别
1. 通过上面的例子我们也可以看出,v-if是根据条件是否加载对应的DOM节点,而v-show是一定会加载对应的节点,只是根据条件是否显示,相当于是display。
2. 如果项目需求场景中切换频率比较高,建议使用v-show,否则建议使用v-if。
3. 有些时候我们需要控制某个代码块是否渲染,为了不破坏元素的DOM结构,这时候我们可以使用template来充当容器,而且在渲染的时候template是不会渲染成DOM节点的。
4. template上面如果要使用条件渲染指令的话,只能使用v-if,不能使用v-show。
列表渲染
列表渲染其实本质上就是模板内容的循环加载,主要是使用v-for指令来实现的。其中v-for可以在很多主体上,比如,对象,数组等。
v-for的几种方式
⏰ v-for里使用数组
在v-for中使用数组,和js中相同,有item, index,其中item表示数组项, index表示索引。
<div v-for="(item, index) in arr" :key="index"> {{item}}-{{index}} </div> data () { return { arr: [12, 22, 32, 42, 52, 62] } }
效果如下:
⚠️ 特别注意: (item, index) in arr中的item和index的顺序不能写错。否则模板里面的内容不能正确渲染
⏰ v-for里使用对象
在v-for中使用对象,也有两个关键变量,但是和数组中不同的是,不再是in关键字了,而是of关键字,而且有三个变量是value,key和index, value表示对象的属性值,key表示对象的属性, index表示索引
<div v-for="(value, key, index) of obj" :key="key"> {{key}}-{{value}}-{{index}} </div> data () { return { obj: { name: '张三', age: 18, sex: 'man' } } }
效果如下:
⚠️ 特别注意:(value, key) of obj中的value和key的顺序不能写错,否则可能不能正确渲染出来。
⏰ v-for循环固定次数
如果只是想要让某些模板重复渲染几次,那么就可以使用v-for循环固定次数。使用方法是index of num(次数)。
<div v-for="index of 5" :key="index"> {{index}} </div>
效果如下:
⚠️ 特别注意:这种方法只有一个关键变量index,不能有其他变量。否则浏览器会报错。
⏰ v-for里使用字符串
v-for里不仅可以使用数组,对象,其实也可以使用字符串。
<div v-for="index of 'thastring'" :key="index"> {{index}} </div>
效果如下:
⚠️ 特别注意:使用v-for遍历字符串的时候,字符串之间不能有空格,而且字符串的每一项之间不能有重复。由此种种,这种方式基本上不会用到
⏰ 小结
1. 很多时候,后端接口给我们返回动态数据,然后需要按照一定模板格式将这些数据动态加载出来,这时候就需要用到列表渲染了。
2. 列表渲染虽然有好几种用法,但是在实际开发中我们最常用的还是使用数组和对象的方式。
列表渲染中的过滤
上面主要是介绍列表渲染的一些常见的使用方法。这里我们开始介绍一些列表渲染中关于列表数据的处理。 很多时候,我们从后端拿到了很多数据,但是往往在渲染的时候我们并不是要按照接口返回的数据展示,而是要将数据进行处理之后再渲染出来,比如:过滤或者排序。
列表的过滤主要会用到计算属性。
<div v-for="(item, index) in newArr" :key="index"> {{ item }}-{{ index }} </div> data () { return { arr: [1, 13, 5, 2, 8, 23, 16, 34] } }, computed: { newArr () { return this.arr.filter(item => item > 1) } },
效果如下:
列表渲染中的排序
排序其实和过滤差不多,也是会用到计算属性,计算属性可以监听到原来数据的变化及时计算并响应出来。
<div v-for="(item, index) in newArr" :key="index"> {{item}}-{{index}} </div> data () { return { arr: [1, 13, 5, 2, 8, 23, 16, 34] } }, computed: { newArr () { const arr = this.arr arr.sort((a, b) => { return a - b }) return arr } }
效果如下:
列表渲染中的唯一索引key
我们都知道通常在列表渲染中使用v-for指令时,需要指定唯一索引key,那为什么要指定唯一索引key呢?这就要从DOM Diff说起,由于篇幅原因,这里我们就介绍一下 dom diff的流程,后面我们再从源码角度,深入介绍DOM Diff的实现原理。
⏰ DOM Diff的流程
当我们的数据发生变化的时候,模板也会相应地更新,那么这时候就需要使用DOM Diff, 主要流程如下:
- 根据旧的数据生成对应的虚拟DOM(也就是DOM对象)
- 如果数据更新了,修改对应的虚拟DOM的数据,生成新的虚拟DOM
- 然后比较新旧两个虚拟DOM,这个过程是一层层地去比较,寻找的有变化的部分,根据key渲染到真正的DOM节点上
这样如果没有变化的节点,它的虚拟DOM是没有变化的,这时候就不需要重新渲染DOM,如果需要删除的DOM,就直接根据key删除对应的DOM,这样就能大大提高渲染效率,也能避免由于没有唯一索引导致的渲染错误。
⏰ 使用key时需要注意的地方
- 为同一层的相同类型的元素添加key属性 为同一层相同类型的元素添加key值,那么在添加或者删除的时候就可以根据key值直接对DOM进行添加和删除,这样能够大大提高效率
- key不能是index下标值 当数组发生增加和删除时,打乱了它的顺序,它的下标是会发生改变的,因此不能保证修改数据前,相同key对应的是同一个DOM。因此在使用key时,建议使用唯一值。
- 设置key 如果数组的下标不会发生变化,那么直接使用index即可,如果数组的下标会发生变化,建议使用唯一索引,比如后端接口返回的id或者其他前端的唯一标识属性。如果不设置key值,那么vue会默认将index作为key值。
数组更新检测
这块也是基于vue的数组响应式原理来实现数组的更新的。
⏰ 变更数组
下面这些方法是更新原来的数组,是可以实现视图的即时更新。
<div class="hello"> <div v-for="(item, index) in arr" :key="index"> {{item}}-{{index}} </div> <button @click="updateInfo">更新数组</button> </div> data () { return { arr: [1, 13, 5, 2, 8, 23, 16, 34] } }, methods: { updateInfo () { // this.arr.push(1) // this.arr.pop() // this.arr.shift() // this.arr.unshift(10) // this.arr.splice(0, 1) // this.arr.sort() // this.arr.reverse() this.arr = [1, 2, 3, 4] } }
效果如下
⏰ 数组替换
下面这些方法会重新返回新的数组,相当于原数组是不变的,因此想要让视图更新,必须重新绑定数组。
<div class="hello"> <div v-for="(item, index) in arr" :key="index"> {{item}}-{{index}} </div> <button @click="updateInfo">替换数组</button> </div>
data () { return { arr: [1, 13, 5, 2, 8, 23, 16, 34] } }, methods: { updateInfo () { // this.arr = this.arr.filter(item => item > 10) // this.arr = this.arr.concat([4, 6, 12, 30]) this.arr = this.arr.slice(0, 1) } }
效果如下
v-for的其他使用
v-for除了上面我们介绍的可以用在标签上,还有一些使用我们也应该要注意。
⏰ v-for用在template上
v-for也是可以使用在template上,因为template也是一个标签,只是它不会渲染成真正的DOM节点。
<template v-for="(item, index) in arr"> <div :key="index"> {{item}}-{{index}} </div> </template> data () { return { arr: [1, 13, 5, 2, 8, 23, 16, 34] } },
效果如下:
⚠️ 特别注意:在vue2中,如果将v-for用在template上,那么唯一标识key是不能写在template上的。因为template不会渲染成真正DOM,而key需要写在真正DOM上。
⏰ v-for用在组件上
这种方式一般适用于在循环遍历数据,然后将每一项的数据传到对应的组件。
parent.vue
// parent.vue <div class="hello"> <Child v-for="(item, index) in arr" :key="index" :value="item"></Child> </div> components: { Child }, data () { return { arr: [1, 13, 5, 2, 8, 23, 16, 34] } }
-
child.vue
// child.vue <template> <div class="child"> <span>{{value}}</span> </div> </template> <script> export default { name: 'Child', props: { value: '' }, data () { return { } } } </script>
效果如下:
⏰ v-for和v-if同时使用
一般不推荐将v-for和v-if同时使用在同一个元素上,但是在某些时候这样写是可以的,并且可以实现遍历加过滤的效果。
<template v-for="(item, index) in arr" v-if="item > 5"> <div :key="index"> {{item}}-{{index}} </div> </template>
效果如下:
⚠️ 从上面的效果我们可以看出,v-for和v-if同时使用的话,v-for的优先级要比v-if高。