前言
当在我们做微信小程序项目时会遇到有多个端口的项目需求,然而多个端口意味着多个导航栏。但微信小程序仅支持使用app.json创建一个导航栏(如下图)
![](https://i-blog.csdnimg.cn/blog_migrate/6da0f3adc5da517bf1ecd75d80ba2061.png)
在app.json中配置的tabbar
![](https://i-blog.csdnimg.cn/blog_migrate/54b5fd8373e3242fbda7c7f09a874a3d.png)
app.json
所以我们只能自己制作导航栏并且使用页面路由方式来进行页面跳转(如wx.navigateTo; wx.redirectTo; wx.switchBack等等)这样做的弊端就是页面数量过多,重叠WMXL\WXSS\JS的代码过多影响小程序的整体性能。(如下图)
自己制作的导航栏:
![](https://i-blog.csdnimg.cn/blog_migrate/148ee57fa7948e54c4d6dbdfb7298178.png)
使用外部组件创建的tabbar或自己创建的tabbar
需要的页面:
![](https://i-blog.csdnimg.cn/blog_migrate/8a5da14ca4d72f3a6a9213a3bb8e7cfd.png)
根据自建tabbar需要创建的页面数量
那么有什么办法既能只用一个页面,又可以实现使用导航栏切换页面内容的方法吗?答案肯定是有的,并且实现思路和方法都很简单!
使用vant-weapp组件库
如何引入外部组件库我在这里就不赘诉了,按照下面这个链接做就好了
https://vant-contrib.gitee.io/vant-weapp/#/quickstart
![](https://i-blog.csdnimg.cn/blog_migrate/fce45220e12b6f76f62c4442e2911771.png)
我们需要使用到van-tabbar和van-tabbar这两个外部组件,这些组件支持的API也可以在下面找到。
![](https://i-blog.csdnimg.cn/blog_migrate/ce3f23dcfadf49edceb522ec95f80aba.png)
那么我们该如何使用这个组件呢?我们要在需要使用这个组件的页面json文件中引入。例如我需要在approval页面中使用这个外部组件。
![](https://i-blog.csdnimg.cn/blog_migrate/06d0d7762ad3f8478b48ccdffa4ee538.png)
引入完成后在WXML中使用就好了,这里我就直接放代码了。这里需要注意的是图片image的src路径不能在使用"../../icon/..."之类的格式了,需要使用url地址(http:.....)
我使用的是SM.MS来上传我的图片并且生成其URL。
![](https://i-blog.csdnimg.cn/blog_migrate/2a60fb5c5446274251f5e654a590697b.png)
<!-- approval.wxml -->
<!-- 导航栏 -->
<van-tabbar active="{{ active }}" bind:change="onChange" active-color="red" inactive-color="#000">
<van-tabbar-item info="{{item0}}">
<image
slot="icon"
src="{{ approval.normal }}"
mode="aspectFit"
style="width: 50px; height: 30px;"
/>
<image
slot="icon-active"
src="{{ approval.active }}"
mode="aspectFit"
style="width: 50px; height: 30px;"
/>
待审批
</van-tabbar-item>
<van-tabbar-item info="{{item1}}">
<image
slot="icon"
src="{{ pass.normal }}"
mode="aspectFit"
style="width: 50px; height: 30px;"
/>
<image
slot="icon-active"
src="{{ pass.active }}"
mode="aspectFit"
style="width: 50px; height: 30px;"
/>
已通过
</van-tabbar-item>
<van-tabbar-item info="{{item2}}">
<image
slot="icon"
src="{{ reject.normal }}"
mode="aspectFit"
style="width: 50px; height: 30px;"
/>
<image
slot="icon-active"
src="{{ reject.active }}"
mode="aspectFit"
style="width: 50px; height: 30px;"
/>
已驳回
</van-tabbar-item>
<van-tabbar-item info="{{item3}}">
<image
slot="icon"
src="{{ end.normal }}"
mode="aspectFit"
style="width: 50px; height: 30px;"
/>
<image
slot="icon-active"
src="{{ end.active }}"
mode="aspectFit"
style="width: 50px; height: 30px;"
/>
已结束
</van-tabbar-item>
</van-tabbar>
Page({
data: {
list:[],
approval: {
normal: 'https://s2.loli.net/2023/02/13/Am8Y9LFgj5T4CNS.png',
active: 'https://s2.loli.net/2023/02/13/fJgW8xVoIw56LjD.png',
},
pass: {
normal: 'https://s2.loli.net/2023/02/13/zaeYGD4Mg5W1T8q.png',
active: 'https://s2.loli.net/2023/02/13/OUgZo6qGWRNB8Ib.png',
},
reject: {
normal: 'https://s2.loli.net/2023/02/13/BhgYDtPEwlbRq45.png',
active: 'https://s2.loli.net/2023/02/13/RabTeAkgXUjGoPf.png',
},
end:{
normal: 'https://s2.loli.net/2023/02/13/89GOxF7mbipH4eA.png',
active: 'https://s2.loli.net/2023/02/13/1EmXdBWlijUQa5p.png',
},
//tabar的索引,0是待审批/1是已通过/2是已驳回/3是已结束
active:0,
//item是tabar右上的数字,0/1/2/3分别对应三个tabar-item,有几个记录就会显示数字几
item0:'',
item1:'',
item2:'',
item3:'',
},
//tabar改变函数
onChange(event) {
this.setData({
active: event.detail
});
//每次赋完值重新渲染一遍页面
this.onLoad()
},
onLoad(options) {
....
....
},
....
....
....
})
当你完成上诉步骤后就可以看到这样的导航栏。
![](https://i-blog.csdnimg.cn/blog_migrate/8181c3df7720a9f15a40e59d6400aab8.png)
使用vant-weapp组件库创建的tabbar
合理使用条件渲染达到无需切换页面来显示多种内容的目的
项目场景:
使用云开发调取数据库所有符合要求的记录并且返回记录的个数(用于提示用户),如果记录个数大于零则显示相关记录,若等于零则返回无活动记录界面。点击导航栏切换页面实则修改记录需符合的要求。假如这么说比较抽象,那么下面我将以实例来说明。
假设每条活动记录都有自己的状态值(state),当活动处于待审批的时候state=0,已通过的时候state=1,以此类推已驳回和已结束。
当我点击导航栏的已通过时,所调取的数据是state=1的数据,并保存记录的条数。假如没有state=1的活动则在导航栏的右上角显示0,并且显示无活动记录(如下图)
![](https://i-blog.csdnimg.cn/blog_migrate/4aae8a0f02436ee92505c07677d6bb82.png)
![](https://i-blog.csdnimg.cn/blog_migrate/f78568c413e9087ae572a1d5efb817f3.png)
若有活动记录则展示出来,右上角显示符合条件的记录条数
核心思想就是条件渲染(wx:if),多个条件渲染的嵌套和并列就能很好的实现该功能。
![](https://i-blog.csdnimg.cn/blog_migrate/0d698ac54dc116c7e25e43297668bfc0.png)
![](https://i-blog.csdnimg.cn/blog_migrate/f446b00ce99343fe7dcc5f1bdd01f591.png)
![](https://i-blog.csdnimg.cn/blog_migrate/4497850792a6e100f41dc2b2f73b5473.png)
整个页面的wxml/wxss/js代码我都放在下面了,需要的自取~
<!-- 采用的是flexbos布局 -->
<view class="container">
<view class="container_content">
<view class="box">
<view class="mine_application">
<!-- 活动标题 -->
<!-- 待审批的标题头 -->
<view wx:if="{{ active == 0 }}">
<view class="mine_application_title">
待审批的活动<image src="../../icon/work-box.png" style="width: 50px;height: 40px;position: absolute; right: 20px; top: 0px;" bindtap="waitDownload"></image>
</view>
</view>
<!-- 已通过的标题头 -->
<view wx:if="{{ active == 1}}">
<view class="mine_application_title">
已审批的活动<image src="../../icon/work-box.png" style="width: 50px;height: 40px;position: absolute; right: 20px; top: 0px;" bindtap="passDownload"></image>
</view>
</view>
<!-- 已驳回的标题头 -->
<view wx:if="{{ active == 2}}">
<view class="mine_application_title">
已驳回的活动
</view>
</view>
<!-- 已结束的标题头 -->
<view wx:if="{{ active == 3}}">
<view class="mine_application_title">
已结束的活动
</view>
</view>
<!-- 活动内容 点击可跳转至详情页面 -->
<!-- 待审批活动内容 -->
<view wx:if="{{ active == 0}}">
<!-- 当右上角数字为0的时候显示 -->
<view wx:if="{{ item0 == 0}}">
<image src="https://s2.loli.net/2023/02/13/sm2ftjSYgD5QTr7.png" class="noData"></image>
<view class="tip">很抱歉,暂无活动记录哦</view>
</view>
<view class="mine_application_content" wx:for="{{list}}" wx:key="_id">
<view class="event" bindtap="goDetail" data-id="{{item._id}}">
<view class="">活动名称:{{item.a1_huodongName}}</view>
<view class="eventTime">活动起始时间:{{item.a2_startTime}}</view>
<view class='organization'>归属组织:{{item.g1_orderInstitute}}</view>
<view class="name">负责人姓名:{{item.b1_fzrName}}</view>
</view>
<!-- 右上角的状态栏 -->
<!-- 状态为3代表活动总结审核中,0为初次审核中 -->
<block wx:if="{{item.state==0}}">
<!-- 审核中 -->
<view class="state_0">
<view class="state_content">审核中</view>
</view>
<!-- 活动下方的小点 -->
<image src="../../icon/yellow.png" style="width: 11px;height: 11px;position: absolute;left: 15px;bottom: 15px;"></image>
</block>
<block wx:if="{{item.state==3}}">
<!-- 已通过 -->
<view class="state_1">
<view class="state_content">已通过</view>
</view>
<!-- 活动下方的小点 -->
<image src="../../icon/green.png" style="width: 11px;height: 11px;position: absolute;left: 15px;bottom: 15px;"></image>
<view class="next_location">
<button class="button_detail" size="mini">
<view>
活动总结审核中..
</view>
</button>
</view>
</block>
</view>
</view>
<!-- 已通过活动内容 -->
<view wx:if="{{ active == 1}}">
<!-- 当右上角数字为0的时候显示 -->
<view wx:if="{{ item1 == 0}}">
<image src="https://s2.loli.net/2023/02/13/sm2ftjSYgD5QTr7.png" class="noData"></image>
<view class="tip">很抱歉,暂无活动记录哦</view>
</view>
<view class="mine_application_content" wx:for="{{list}}" wx:key="_id">
<view class="event" bindtap="goDetail" data-id="{{item._id}}">
<view class="">活动名称:{{item.a1_huodongName}}</view>
<view class="eventTime">活动起始时间:{{item.a2_startTime}}</view>
<view class='organization'>归属组织:{{item.g1_orderInstitute}}</view>
<view class="name">负责人姓名:{{item.b1_fzrName}}</view>
</view>
<block wx:if="{{item.state==1}}">
<!-- 已通过 -->
<view class="state_1">
<view class="state_content">已通过</view>
</view>
<!-- 活动下方的小点 -->
<image src="../../icon/green.png" style="width: 11px;height: 11px;position: absolute;left: 15px;bottom: 15px;"></image>
</block>
</view>
</view>
<!-- 已驳回活动内容 -->
<view wx:if="{{ active == 2}}">
<!-- 当右上角数字为0的时候显示 -->
<view wx:if="{{ item2 == 0}}">
<image src="https://s2.loli.net/2023/02/13/sm2ftjSYgD5QTr7.png" class="noData"></image>
<view class="tip">很抱歉,暂无活动记录哦</view>
</view>
<view class="mine_application_content" wx:for="{{list}}" wx:key="_id">
<view class="event" bindtap="goDetail" data-id="{{item._id}}">
<view class="">活动名称:{{item.a1_huodongName}}</view>
<view class="eventTime">活动起始时间:{{item.a2_startTime}}</view>
<view class='organization'>归属组织:{{item.g1_orderInstitute}}</view>
<view class="name">负责人姓名:{{item.b1_fzrName}}</view>
</view>
<block wx:if="{{item.state==2}}">
<!-- 已驳回 -->
<view class="state_2">
<view class="state_content">已驳回</view>
</view>
<!-- 活动下方的小点 -->
<image src="../../icon/red.png" style="width: 11px;height: 11px;position: absolute;left: 15px;bottom: 15px;"></image>
<view class="reject_location">
<button class="button_detail" size="mini" bindtap="goDetail" data-id="{{item._id}}">驳回详情 >
</button>
</view>
</block>
</view>
</view>
<!-- 已结束活动内容 -->
<view wx:if="{{ active == 3}}">
<!-- 当右上角数字为0的时候显示 -->
<view wx:if="{{ item3 == 0}}">
<image src="https://s2.loli.net/2023/02/13/sm2ftjSYgD5QTr7.png" class="noData"></image>
<view class="tip">很抱歉,暂无活动记录哦</view>
</view>
<view class="mine_application_content" wx:for="{{list}}" wx:key="_id">
<view class="event" bindtap="goDetail" data-id="{{item._id}}">
<view class="">活动名称:{{item.a1_huodongName}}</view>
<view class="eventTime">活动起始时间:{{item.a2_startTime}}</view>
<view class='organization'>归属组织:{{item.g1_orderInstitute}}</view>
<view class="name">负责人姓名:{{item.b1_fzrName}}</view>
</view>
<!-- 状态为4为活动总结报告已审批,3为已提交活动总结报告 -->
<block wx:if="{{item.state==4}}">
<!-- 活动报告已审批通过 -->
<view class="state_4">
<view class="state_content">已结束</view>
</view>
<!-- 活动下方的小点 -->
<image src="../../icon/grey.png" style="width: 11px;height: 11px;position: absolute;left: 15px;bottom: 15px;"></image>
</block>
</view>
</view>
</view>
</view>
<!-- 导航栏 -->
<van-tabbar active="{{ active }}" bind:change="onChange" active-color="red" inactive-color="#000">
<van-tabbar-item info="{{item0}}">
<image
slot="icon"
src="{{ approval.normal }}"
mode="aspectFit"
style="width: 50px; height: 30px;"
/>
<image
slot="icon-active"
src="{{ approval.active }}"
mode="aspectFit"
style="width: 50px; height: 30px;"
/>
待审批
</van-tabbar-item>
<van-tabbar-item info="{{item1}}">
<image
slot="icon"
src="{{ pass.normal }}"
mode="aspectFit"
style="width: 50px; height: 30px;"
/>
<image
slot="icon-active"
src="{{ pass.active }}"
mode="aspectFit"
style="width: 50px; height: 30px;"
/>
已通过
</van-tabbar-item>
<van-tabbar-item info="{{item2}}">
<image
slot="icon"
src="{{ reject.normal }}"
mode="aspectFit"
style="width: 50px; height: 30px;"
/>
<image
slot="icon-active"
src="{{ reject.active }}"
mode="aspectFit"
style="width: 50px; height: 30px;"
/>
已驳回
</van-tabbar-item>
<van-tabbar-item info="{{item3}}">
<image
slot="icon"
src="{{ end.normal }}"
mode="aspectFit"
style="width: 50px; height: 30px;"
/>
<image
slot="icon-active"
src="{{ end.active }}"
mode="aspectFit"
style="width: 50px; height: 30px;"
/>
已结束
</van-tabbar-item>
</van-tabbar>
</view>
</view>
.mine_application{
margin-left: 15px;
margin-right: 15px;
}
.mine_application_title{
border-bottom: 5rpx solid #A6A6A6;
font-size: 28px;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
.box{
margin-bottom: 50px;
}
.mine_application_content{
height: 150px;
width: 100%;
display: flex;
position: relative;
box-shadow: 16rpx 8rpx 24rpx rgba(212,48,48, 0.1);
margin-top: 15px;
border-radius: 15px;
}
.event{
font-size: 20px;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
position: relative;
margin:15px;
width: 90%;
flex: 1;
}
.eventTime{
margin-top: 5px;
font-size: 14px;
color: #A0A9BD;
}
.state_0{
float: right;
width: 80px;
height: 40px;
background-color:#FFC300;
border-radius: 0 15px 0 15px;
}
.state_1{
width: 80px;
height: 40px;
background-color:#43CF7C;
border-radius: 0 15px 0 15px;
z-index: 2;
}
.state_content{
position: relative;
margin-top:10px ;
margin-left: 15px;
font-size: 12;
color: white;
}
.button_detail{
background-color: white;
color:#727885;
}
.organization{
font-size: 15px;
color:#FF5733;
margin-top: 5px;
}
.container{
position: relative;
}
.container_content{
position: relative;
min-height: 100vh;
box-sizing: border-box;
padding-bottom: 60rpx;
padding-top: 0rpx;
}
.tabar{
width: 100%;
text-align: center;
letter-spacing: 4rpx;
position: absolute;
bottom: 0;
}
.name{
font-size: 17px;
font-weight: 200;
color: #174099;
}
.next_location{
width:150px;
height:40px;
position: absolute;
z-index: 1;
bottom: 0px;
right: 0px;
}
.noData{
height: 50vh;
width: 100%;
position: absolute;
top: 10vh;
margin-top: 50rpx;
}
.tip{
position: relative;
margin-top: 60vh;
font-size: 18px;
color:gray;
text-align: center;
}
const db = wx.cloud.database()
const _ = db.command
const t = new Date().getTime().toString().slice(0, -3);
Page({
data: {
list:[],
approval: {
normal: 'https://s2.loli.net/2023/02/13/Am8Y9LFgj5T4CNS.png',
active: 'https://s2.loli.net/2023/02/13/fJgW8xVoIw56LjD.png',
},
pass: {
normal: 'https://s2.loli.net/2023/02/13/zaeYGD4Mg5W1T8q.png',
active: 'https://s2.loli.net/2023/02/13/OUgZo6qGWRNB8Ib.png',
},
reject: {
normal: 'https://s2.loli.net/2023/02/13/BhgYDtPEwlbRq45.png',
active: 'https://s2.loli.net/2023/02/13/RabTeAkgXUjGoPf.png',
},
end:{
normal: 'https://s2.loli.net/2023/02/13/89GOxF7mbipH4eA.png',
active: 'https://s2.loli.net/2023/02/13/1EmXdBWlijUQa5p.png',
},
//tabar的索引,0是待审批/1是已通过/2是已驳回/3是已结束
active:0,
//item是tabar右上的数字,0/1/2/3分别对应三个tabar-item,有几个记录就会显示数字几
item0:'',
item1:'',
item2:'',
item3:'',
},
//tabar改变函数
onChange(event) {
this.setData({
active: event.detail
});
this.onLoad()
},
onLoad(options) {
//当选择的是“待审批”执行
if(this.data.active == 0){
db.collection("huoDong")
.where({
state:_.or(0,3),
})
.get()
.then(res=>{
console.log('查询数据库成功',res.data)
//将返回的res.data里面的值赋值给list,覆盖除了所选tabar-item以外所有item的值
this.setData({
list :res.data,
item0 :res.data.length,
item1:'',
item2:'',
item3:''
})
console.log("这是list",this.data.list)
})
}
//当选择的是“已通过”执行
if(this.data.active == 1){
db.collection("huoDong")
.where({
state:1
})
.get()
.then(res=>{
console.log('查询数据库成功',res.data)
//将返回的res.data里面的值赋值给list
this.setData({
list :res.data,
item0:'',
item1:res.data.length,
item2:'',
item3:'',
})
console.log("这是list",this.data.list)
})
}
//当选择的是“已驳回”执行
if(this.data.active == 2){
db.collection("huoDong")
.where({
state:2
})
.get()
.then(res=>{
console.log('查询数据库成功',res.data)
//将返回的res.data里面的值赋值给list
this.setData({
list :res.data,
item0:'',
item1:'',
item2:res.data.length,
item3:'',
})
console.log("这是list",this.data.list)
})
}
//当选择的是“已结束”执行
if(this.data.active == 3){
//调用云函数来突破返回数据库的条数只有20条的限制
wx.cloud.callFunction({
name:'getAll'
})
.then(res=>{
console.log('成功',res)
this.setData({
list :res.result.data,
item0:'',
item1:'',
item2:'',
item3:res.result.data.length,
})
})
.catch(res=>{
console.log("失败",res);
})
}
},
onPullDownRefresh() {
},
onReachBottom() {
},
goDetail(e){
console.log("点击了详情页面,将展示活动的id ",e)
wx.navigateTo({
// 跳转到活动详情页面并携带活动id
url: '/pages/TeventDetail/TeventDetail?id=' +e.currentTarget.dataset.id
})
},
})
最终效果
只用了一个页面就完成了显示四个不同页面的任务,页面数量减小,重叠的代码块大大减少,主包的大小减小,性能得到了很好的优化,用户的整体体验得到改善。
![](https://i-blog.csdnimg.cn/blog_migrate/5ccf79314e7171db4ca02de4a7e1b448.png)
从之前所需的四个页面整合成了一个页面,大大减小了代码的重叠率
![](https://i-blog.csdnimg.cn/blog_migrate/63177f8a7fcf24e2c04b8af9158ee7ac.png)
当点击tabbar栏时,看似跳转了页面实则任在当前页面
结语
如果有疑问欢迎大家留言讨论,你如果觉得这篇文章对你有帮助可以给我一个免费的赞吗?我们之间的交流是我最大的动力!