前文讲解了uni-app事件绑定,本文讨论下条件渲染和列表渲染。

条件渲染主要指令:v-if和v-show,列表渲染指令:v-for。

一、条件渲染

1、指令:v-if

v-if 指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回 truthy 值的时候被渲染。

在 JavaScript 中,truthy(真值)指的是在布尔值上下文中,转换后的值为真的值。

所有值都是真值,除非它们被定义为 假值(即除 false、0、””、null、undefined 和 NaN 以外皆为真值)。

示例:

<template>
    <view>
        <view v-if="show">能看到</view>
    </view>
</template>

<script>
    export default {
        data() {
            return {
                show: true,
                //只有其值为:false、0、""、null、undefined 和 NaN为false,其它值都为ture
                //show: 10 //照样会显示
            }
        },
        onLoad() {},
        methods: {}
    }
</script>

<style>

</style>

示例中定义变量show,只有当值为:false、0、””、null、undefined 和 NaN时才不会渲染,其它值都会渲染。

当然,v-if中也支持三元运算

<template>
    <view>
        <view v-if="age>=18? true:false">已成年</view>
    </view>
</template>

<script>
    export default {
        data() {
            return {
                age: 18,
            }
        },
        onLoad() {},
        methods: {}
    }
</script>

<style>

</style>

2、指令:v-else

v-if与v-else组合使用

<template>
    <view>
        <view v-if="show">能看到</view>
        <view v-else>看不到</view>
    </view>
</template>

<script>
    export default {
        data() {
            return {
                show: false,
            }
        },
        onLoad() {},
        methods: {}
    }
</script>

<style>

</style>

示例中,根据变量show的值动态渲染不同的内容。

3、指令:v-else-if

类似于 v-else ,v-else-if 也必须紧跟在带 v-if 或者 v-else-if 的元素之后。

<template>
    <view>
        <view v-if="age<18">未成年</view>
        <view v-else-if="age<=60">努力工作</view>
        <view v-else-if="age<=120">安享晚年</view>
        <view v-else>妖怪</view>
    </view>
</template>

<script>
    export default {
        data() {
            return {
                age: 18,  //未成年:小于18;努力工作:[18-60];安享晚年:(60-120];妖怪:120岁以上
            }
        },
        onLoad() {},
        methods: {}
    }
</script>

<style>

</style>

示例中可以看到,可以包含多个 v-else-if 指令。

4、条件渲染分组

因为 v-if 是一个指令,所以必须将它添加到一个元素上。

但是如果想切换多个元素呢?此时可以把一个 template 元素当做不可见的包裹元素,并在上面使用 v-if。最终的渲染结果将不包含 template 元素。

<template>
    <view>  <!--所有元素必须放在view包裹-->
        <template v-if="show">  <!--不会渲染包裹对象,渲染内部的内容-->
            <view>标题</view>
            <view>内容:我的外层不会渲染</view>
        </template>
        
        <view v-if="show">  <!--会渲染出view,包裹里边的内容-->
            <view>标题</view>
            <view>内容:我的外层会渲染</view>
        </view>
    </view>

</template>

<script>
    export default {
        data() {
            return {
                show: true,
            }
        },
        onLoad() {},
        methods: {}
    }
</script>

<style>

</style>

示例所谓:<template>标签将不会渲染出来,读者自行拷贝代码运行后,在浏览器中通过源码视图查看对比。

5、指令:v-show

v-show 是一个根据条件展示元素选项的指令 。用法大致和 v-if 一样:

<view v-show="show">显示</view>

不同的是带有 v-show 的元素始终会被渲染并保留在 DOM 中。

v-show 只是简单地切换元素的 CSS 属性的 display 。

注意,v-show 不支持 template 元素,也不支持 v-else。

6、v-if与v-show区别

示例:

<template>
    <view>
        <view v-if="show">v-if</view>
        <view v-show="show">v-show</view>
    </view>

</template>

<script>
    export default {
        data() {
            return {
                show: false,
            }
        },
        onLoad() {},
        methods: {}
    }
</script>

<style>

</style>

以上示例,因为show为false,所以页面上不会有显示。

但是打开浏览器查看源文件,发现v-show对应的view渲染出来了,只是css对应的display:none没有显示而已,实际dom已经渲染了。

v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。

v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做,直到条件第一次变为真时,才会开始渲染条件块。

相比之下,v-show 就简单得多,不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换,来控制元素的显示和隐藏。

根据应用场景选择 v-if 有更高的切换开销,如果在运行时条件很少改变,则使用 v-if 较好。 v-show 有更高的初始渲染开销。如果需要非常频繁地切换,则使用 v-show 较好。

注意:

不推荐同时使用 v-if 和 v-for。 当 v-if 与 v-for 一起使用时,v-for 具有比 v-if 更高的优先级。

二、列表渲染

列表渲染采用指令:v-for

1、在数组里使用v-for

v-for 指令可以实现基于一个数组来渲染一个列表。

v-for 指令需要使用 item in items 形式的特殊语法,其中 items 是源数据数组,而 item 则是被迭代的数组元素的别名。

第一个参数 item 则是被迭代的数组元素的别名。 第二个参数,即当前项的索引 index ,是可选的。

基本示例如下:

<template>
    <view>
        <view v-for="(friend,index) in friends">
            {{index}}--{{friend}}
        </view>
    </view>
</template>
<script>
    export default {
        data() {
            return {
                friends: ["lucy","lily"] //朋友数组
            }
        }
    }
</script>

示例中friends是一个字符串数组,通过v-for遍历并输出数组中的朋友。

当然第二个参数index索引是可以选的,所以在一般情况下也可以不写:

<template>
    <view>
        <view v-for="friend in friends">
            {{friend}}
        </view>
    </view>
</template>
<script>
    export default {
        data() {
            return {
                friends: ["lucy","lily"] //朋友数组
            }
        }
    }
</script>

2、在v-for里使用对象

你也可以用 v-for 来遍历一个对象的 property。 第一个参数 value 是被迭代的数组元素的别名。 第二个参数为 property 名称 (也就是键名)。 第三个参数作为索引。

<template>
    <view>
        <view v-for="(value, name, index) in book">
            {{ index }}. {{ name }}: {{ value }}
        </view>
    </view>
</template>
<script>
    export default {
        data() {
            return {
                book: {
                    title: 'mysql删除到跑路',
                    author: 'heima',
                    publisheAt: "2021-1-1"
                }
            }
        }
    }
</script>

注意,如果要缺省参数,那么参数只能从右边开始减少。

前边演示的数组元素也可以是对象,如下实例:

<template>
    <view>
        <view v-for="friend in friends">
            {{friend.name}}--{{friend.age}}
        </view>
    </view>
</template>
<script>
    export default {
        data() {
            return {
                friends: [
                    {
                        name:"lucy",
                        age:"18"
                    },{
                        name:"lily",
                        age:"18"
                    }
                    ] 
            }
        }
    }
</script>

注意,在一些特殊情况下(比如多重循环),如果不写index,将导致一些意想不到的bug,见第6点。

3、列表渲染分组

类似于 v-if,你也可以利用带有 v-for 的 template 来循环渲染一段包含多个元素的内容。比如:

<template>
    <view>
        <template v-for="(friend,index) in friends">
            <view>{{friend.name}}</view>
            <view>{{friend.age}}</view>
        </template>
    </view>
</template>
<script>
    export default {
        data() {
            return {
                friends: [{
                    name: "lucy",
                    age: "18"
                }, {
                    name: "lily",
                    age: "18"
                }]
            }
        }
    }
</script>

4、在组件上使用v-for

在自定义组件上,你可以像在任何普通元素上一样使用 v-for 。

 <my-component v-for="item in items" :key="item.id"></my-component>

当在组件上使用 v-for 时,key是必须的。

5、v-for中的key

当 Vue 正在更新使用 v-for 渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。

如果列表中项目的位置会动态改变或者有新的项目添加到列表中,并且希望列表中的项目保持自己的特征和状态(如 input 中的输入内容,switch 的选中状态),需要使用 :key 来指定列表中项目的唯一的标识符。

:key 的值以两种形式提供

使用 v-for 循环 array 中 item 的某个 property,该 property 的值需要是列表中唯一的字符串或数字,且不能动态改变。 ​ 使用 v-for 循环中 item 本身,这时需要 item 本身是一个唯一的字符串或者数字

<template>
    <view>
        <!-- array 中 item 的某个 property -->
        <view v-for="(item,index) in objectArray" :key="item.id">
            {{index +':'+ item.name}}
        </view>
        <!-- item 本身是一个唯一的字符串或者数字时,可以使用 item 本身 -->
        <view v-for="(item,index) in stringArray" :key="item">
            {{index +':'+ item}}
        </view>
    </view>
</template>
<script>
    export default {
        data() {
            return {
                objectArray: [{
                    id: 0,
                    name: 'li ming'
                }, {
                    id: 1,
                    name: 'wang peng'
                }],
                stringArray: ['a', 'b', 'c']
            }
        }
    }
</script>
s

当数据改变触发渲染层重新渲染的时候,会校正带有 key 的组件,框架会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率。

如不提供 :key,会报一个 warning, 如果明确知道该列表是静态,或者不必关注其顺序,可以选择忽略。

警告内容为:component lists rendered with v-for should have explicit keys.

当要关注顺序的情况下,如果不提供key,看看会发生什么?

<template>
    <view>
        <view v-for="friend in friends" ><!--:key="friend.id"-->
            <checkbox>{{friend.name}}</checkbox>
        </view>
        <button @click="addSkill">新交朋友</button>
    </view>
</template>
<script>
    export default {
        data() {
            return {
                friends: [{
                    id: 0,
                    name: "lucy",
                },{
                    id: 1,
                    name: "lili",
                },{
                    id: 2,
                    name: "lisa",
                } ]
            }
        },
        methods: {
            addSkill() {
                var arr=this.friends;
                var newId=arr.length+1;
                var newFriend={
                    id:newId,
                    name:"新朋友"+newId
                }
                // this.friends.push(newFriend); //在数组尾部新加项
                this.friends.unshift(newFriend); //在数组头部添加项
            }
        }
    }
</script>

上边示例很简单,页面维护了一个朋友列表,点击按钮将向按钮头部添加新朋友。

看看运行后的效果:

看到问题了吧?

初始时选择的好朋友是lisa,但是每当新认识一个人的时候都会改变我之前选择的值。

这是不对的,无论添加多少人,都不应该改变用户原来的选择。

怎么解决呢?相信你理解了key的作用,一定能知道怎么修复,如果还不清楚,欢迎下边留言区讨论。

6、v-for中的索引index

在以前的版本中多重循环需要显示指定不同的索引index,如果没指定,在浏览器浏览没问题,但是在编译小程序是会报错。

<template>
    <view>
        <view v-for="friend in friends" >
            <view>{{friend.name}}--{{friend.age}}--</view>
            <view>
            <block v-for="skill in friend.skill" > 
                {{skill}},
            </block>
            </view>
        </view>
    </view>
</template>
<script>
    export default {
        data() {
            return {
                friends: [
                    {
                        name:"lucy",
                        age:"18",
                        skill:["c++","java"]
                    },{
                        name:"lily",
                        age:"18",
                        skill:["uni-app","react"]
                    }
                    ] 
            }
        }
    }
</script>

笔者目前使用的HBuilderX3.0.7版本已经不报错了,应该是工具已经做了修复。但是在微信开发者工具可以看到仍然有警告信息,建议加上:key提高渲染性能。

实际开发中建议写得规范一些,把index和key都加上

<template>
    <view>
        <view v-for="(friend,index) in friends" :key=friend.id>
            <view>{{friend.name}}--{{friend.age}}--</view>
            <view>
            <block v-for="(skill,subindex) in friend.skill" :key=skill> 
                {{skill}},
            </block>
            </view>
        </view>
    </view>
</template>
<script>
    export default {
        data() {
            return {
                friends: [
                    {
                        id:0,
                        name:"lucy",
                        age:"18",
                        skill:["c++","java"]
                    },{
                        id:1,
                        name:"lily",
                        age:"18",
                        skill:["uni-app","react"]
                    }
                    ] 
            }
        }
    }
</script>