uni-app 实现自定义底部导航
原博:https://juejin.cn/post/7365533404790341651
在开发微信小程序,通常会使用uniapp自带的tabBar实现底部图标和导航,但现实有少量应用使用uniapp自带的tabBar无法满足需求,这时需要自定义底部tabBar功能。 例如下图的需求,在中间添加一个加号,例如根据不同登录的角色显示不同的tabBar按钮等,这些功能在无法通过 uniapp自带的tabBar实现所以需要写相关组件逻辑。
常规tabBar
常规实现底部导航的效果,可以参考官方文档 uniapp添加tabBar官方文档地址: uniapp.dcloud.net.cn/collocation…
下面将下图为示例写部分代码案例: 在pages.json
写上tabBar 并在List定义好每个页面与页面展示图标,以及不同选中时图标的效果,就可以实现下面页面展示的样式:
案例代码: 注意导航页的图标和页面都必须在根路径下面,因此不能使用网络地址,或分包下的图片和页面。
"tabBar": {
"color": "#bababa",
"selectedColor": "#000000",
"borderStyle": "black",
"backgroundColor": "#ffffff",
"list": [
{
"pagePath": "pages/tabbar/index/index",
"iconPath": "static/images/common/shouye.png",
"selectedIconPath": "static/images/common/shouye-xz.png",
"text": "首页"
},
{
"pagePath": "pages/talent/index",
"iconPath": "static/images/common/task.png",
"selectedIconPath": "static/images/common/task_d.png",
"text": "达人任务"
},
{
"pagePath": "pages/tabbar/facilitator/facilitator",
"iconPath": "static/images/common/facilitator.png",
"selectedIconPath": "static/images/common/facilitator_d.png",
"text": "服务商"
},
{
"pagePath": "pages/aiTools/aiTools",
"iconPath": "static/images/common/aitools.png",
"selectedIconPath": "static/images/common/aitools_d.png",
"text": "创作助手"
},
{
"pagePath": "pages/tabbar/info/info",
"iconPath": "static/images/common/info.png",
"selectedIconPath": "static/images/common/info_d.png",
"text": "我的"
}
]
},
自定义tabBar
梳理业务:
- 去除
pages.json
写上tabBar注释相关代码; - 通过
uni.hideTabBar();
隐藏uniapp自带的tabBar; - 自定义tabBar组件,实现页面相关逻辑;
- 在相关页面引入该组件;
- 根据在页面的onShow方法,当页面显示通过$ref,调用相关逻辑,判断需要显示的底部tabBar按钮和样式。
下面将以下图为案例写相关逻辑:
- 去除
pages.json
写上tabBar注释相关代码,图上写了一个list.pagePath 主要的作用是占位,没别的意义
2.封装tabBar.vue组件
ps:我在
components\tabbar\tabbar.vue
路径下封装tabBar.vue组件,其他的小伙伴可以根据自己的页面需求写在对应位置,例如想实现首页点击进入不同的分包和页面展示不同的tabBar,那么可以根据自己的需求进行调整。
<template>
<view class="tabbar">
<view class="tabbar-item" v-for="(item, index) in list" :key="index" @click="changeTab(index)">
<template v-if="index != 2">
<view class="select" v-if="current == index">
<view>
<view class="i-t position">
<image class="img imgactive" mode="widthFix" :src="item.selectedIconPath"
v-if="current == index">
</image>
<image class="img" mode="widthFix" :src="item.iconPath" v-else></image>
<view class="text active" v-if="current == index">{{ item.text }}</view>
<view class="text" v-else>{{ item.text }}</view>
</view>
</view>
</view>
<view v-else>
<view class="i-t">
<image class="img" mode="widthFix" :src="item.selectedIconPath" v-if="current == index"></image>
<image class="img" mode="widthFix" :src="item.iconPath" v-else></image>
<view class="text active" v-if="current == index">{{ item.text }}</view>
<view class="text" v-else>{{ item.text }}</view>
</view>
</view>
</template>
<!-- 下面是为了解决自定义业务需求,如果is_identity = 3则显示中间的加号,不然显示服务商 -->
<template v-else>
<view class="i-t" v-if="is_identity == 3" >
<image class="img" mode="widthFix" :src="urladdTask" style="width: 140rpx;height: 140rpx;position: absolute;top: -50rpx;"></image>
</view>
<view class="i-t" v-else>
<view class="select" v-if="current == index">
<view>
<view class="i-t position">
<image class="img imgactive" mode="widthFix" :src="item.selectedIconPath"
v-if="current == index">
</image>
<image class="img" mode="widthFix" :src="item.iconPath" v-else></image>
<view class="text active" v-if="current == index">{{ item.text }}</view>
<view class="text" v-else>{{ item.text }}</view>
</view>
</view>
</view>
<view v-else>
<view class="i-t">
<image class="img" mode="widthFix" :src="item.selectedIconPath" v-if="current == index">
</image>
<image class="img" mode="widthFix" :src="item.iconPath" v-else></image>
<view class="text active" v-if="current == index">{{ item.text }}</view>
<view class="text" v-else>{{ item.text }}</view>
</view>
</view>
</view>
</template>
</view>
</view>
</template>
<script>
//引入图片资源
import addTask from '../../static/images/common/addTask.png'
export default {
name: "tabbar",
props: ['current'],
data() {
return {
urladdTask: addTask,
is_identity: 0,
// TODO: 下面list则是你页面上具体展示的底部按钮,根据你的需求和页面进行调整
list: [
{
"pagePath": "pages/tabbar/index/index",
"iconPath": "../../static/images/common/shouye.png",
"selectedIconPath": "../../static/images/common/shouye-xz.png",
"text": "首页"
},
{
"pagePath": "pages/talent/index",
"iconPath": "../../static/images/common/task.png",
"selectedIconPath": "../../static/images/common/task_d.png",
"text": "达人任务"
},
{
"pagePath": "pages/tabbar/facilitator/facilitator",
"iconPath": "../../static/images/common/facilitator.png",
"selectedIconPath": "../../static/images/common/facilitator_d.png",
"text": "服务商"
},
{
"pagePath": "pages/aiTools/aiTools",
"iconPath": "../../static/images/common/aitools.png",
"selectedIconPath": "../../static/images/common/aitools_d.png",
"text": "创作助手"
},
{
"pagePath": "pages/tabbar/info/info",
"iconPath": "../../static/images/common/info.png",
"selectedIconPath": "../../static/images/common/info_d.png",
"text": "我的"
}
]
}
},
created() {
//隐藏tabbar
uni.hideTabBar();
},
mounted() {
},
methods: {
changeTab(e) {
uni.switchTab({
url: '/' + this.list[e].pagePath,
})
}
}
}
</script>
<style>
.tabbar {
font-size: 1.5vh;
position: fixed;
left: 0;
bottom: 0;
z-index: 99;
width: 100%;
height: 6vh;
display: grid;
grid-template-columns: repeat(5, 1fr);
align-items: center;
justify-content: space-around;
background-color: #fff;
padding: 20rpx 0;
}
.tabbar-item {
height: 100%;
display: flex;
align-items: center;
justify-content: center;
position: relative;
}
.img {
height: 3vh;
width: 2.5vh;
}
.text {
text-align: center;
color: #CACACA;
}
.i-t {
display: flex;
flex-direction: column;
justify-items: center;
align-items: center;
}
.select {
position: relative;
}
.text.active {
color: red;
}
.index0 {
width: 80rpx;
height: 80rpx;
}
</style>
- 组件封装完毕需要在对应的页面中引入该组件 例如 下面
index.vue
-
</template> </view> //current则表示选中的状态,例如当前是首页则current为0,如果是第三页则current=2 <tabbar current="0" ref="mytabbar"></tabbar> </view> </template> <script> import tabbar from '@/components/tabbar/tabbar.vue'; export default { components: { tabbar }, }
- 在tabBar.vue组件写上相关页面判断,例如不同的角色则显示不同的按钮,或不同样式。
tabBar.vue
组件中的methods添加一个init函数: -
init() { //获取用户信息 let userinfo = uni.getStorageSync('user'); // 获取角色状态,赋值给is_identity if (userinfo) { this.is_identity = userinfo?.identity; } //...其他调接口等业务处理 }
在第三步的
index.vue
页面中,引入的tabbar组件定义了一个ref="mytabbar"
,可以通过this.$refs.tabBar.init();
的方式来调用tabBar.vue
组件中的methods的init函数。 例如在index.vue
组件下的onShow方法下,当页面显示时候执行tabBar.vue
组件中的methods的init函数async onShow() { await this.getuserinfo(); //其他业务 },