uniapp自定義tabbar的方法(支持中間凸起、角標、動態(tài)隱藏tab和全端適用)
背景
在使用uniapp進行開發(fā)時,tabbar是我們使用的很頻繁的一個組件,但是在特定的平臺會有一些使用上的限制,無法通過一套代碼來做通用平臺的適配。比如說中間按鈕凸起,動態(tài)隱藏某個tab(不同角色展示不同功能),使用字體圖標,數(shù)字角標等,這些功能不是所有平臺都支持。今天我們就用一套代碼來實現(xiàn)這些功能全端支持。
思路
實現(xiàn)思路就是通過通過自定義view來實現(xiàn)我們這個tabbar功能,然后頁面通過組件來展示。通過點擊不同的tab來顯示不同的組件來達到模擬原生tabbar切換效果。那有些人要問了,你咋知道我項目中有多少個tab,這些tab叫什么名字了?那這里就可以利用uniapp提供的組件easycom模式來解決這些問題,只要我們設(shè)置好組件的限制個數(shù)和提前占位名稱,這些問題就迎刃而解。
實現(xiàn)
1、我們現(xiàn)在components(沒有就新建一個components目錄)目錄下新建一個文件夾(我這里叫ctab),然后分別新建一個vue組件和一個js文件。組件可以讓我們在其他地方引用,js文件主要是做配置。

2、新建tab組件,我們組件最多限制5個tab組件,然后需要通過easycom占位來實現(xiàn),所以你需要幾個tab組件就在components目錄下建幾個組件命名為ctabx。如下所示,我這里要展示三個tab:

特別注意這里的tab組件命名一定要符合easycom規(guī)范,不然可能會引起組件引用錯誤。
這里示例一個ctab1寫法:
<template>
<view style="width: 750rpx;height: 300rpx;background-color: red;">
首頁
</view>
</template>
<script>
export default {
name: "ctab1",
data() {
return {};
},
mounted() {},
methods: {}
}
</script>
<style>
</style>
3、tabbar組件ctab.vue實現(xiàn),這里就直接上代碼了,直接copy就能使用,關(guān)鍵地方已加上注釋
<template>
<view>
<!--中間按鈕凸起模式-->
<block v-if="midBtn && midBtn.show">
<!--凸起模式最多展示四個-->
<block v-if="tabs.length < 4">
<ctab1 v-show="sindex == 0"></ctab1>
<ctab2 v-show="sindex == 2"></ctab2>
</block>
<block v-else="tabs.length >= 4">
<ctab1 v-show="sindex == 0"></ctab1>
<ctab2 v-show="sindex == 1"></ctab2>
<ctab3 v-show="sindex == 3"></ctab3>
<ctab4 v-show="sindex == 4"></ctab4>
</block>
<view class="tabbar">
<!--中間按鈕凸起模式tab為3個或者5個-->
<view class="tab-item"
v-for="(item,index) in (tabs.length < 4 ? 3 : 5)"
:key="item"
@click="handleTabClick(index)">
<!--中間按鈕凸起顯示圖片和文字-->
<block v-if="index == floor">
<view :style="'bottom: calc('+(midBtn.offset ? midBtn.offset : '50rpx')+' + env(safe-area-inset-bottom));width: '+(midBtn.width ? midBtn.width : '150rpx')+';height: '+(midBtn.width ? midBtn.width : '150rpx')+';background:'+(midBtn.background ? midBtn.background : '#ffffff')"
class="mid-btn">
<image :src="midBtn.icon"
:style="'width: '+(midBtn.iconwidth ? midBtn.iconwidth : midBtn.width)+';height: '+(midBtn.iconheight ? midBtn.iconheight : midBtn.width)+';'"
@click="handleMidBtn"/>
</view>
<text class="mid-text"
:style="'margin-top: '+(midBtn.textoffset ? midBtn.textoffset : '50rpx;')"
v-show="midBtn.showtext">{{midBtn.text}}</text>
</block>
<!--普通tab這里需要注意index選擇-->
<block v-else>
<view class="c-tab-item">
<text :class="'tab-iconfont iconfont '+(tabs[index < floor ? index : index-1].iconfont)"
:style="'color:'+(sindex == index ? scolor : color)"
v-if="tabs[index < floor ? index : index-1].iconfont"/>
<image :src="sindex == index ? tabs[index < floor ? index : index-1].iconSelect : tabs[index < floor ? index : index-1].icon"
class="tab-icon"
v-else/>
<text class="tab-text"
:style="'color:'+(sindex == index ? scolor : color)">{{tabs[index < floor ? index : index-1].text}}</text>
<view class="corner"
v-show="tabs[index < floor ? index : index-1].mark > 0">{{tabs[index < floor ? index : index-1].mark > 99 ? '99+' : tabs[index < floor ? index : index-1].mark}}</view>
</view>
</block>
</view>
</view>
</block>
<!--普通模式-->
<block v-else>
<block v-if="tabs.length == 1">
<ctab1 v-show="sindex == 0 && tabs[0].show"></ctab1>
</block>
<block v-else-if="tabs.length == 2">
<ctab1 v-show="sindex == 0 && tabs[0].show"></ctab1>
<ctab2 v-show="sindex == 1 && tabs[1].show"></ctab2>
</block>
<block v-else-if="tabs.length == 3">
<ctab1 v-show="sindex == 0 && tabs[0].show"></ctab1>
<ctab2 v-show="sindex == 1 && tabs[1].show"></ctab2>
<ctab3 v-show="sindex == 2 && tabs[2].show"></ctab3>
</block>
<block v-else-if="tabs.length == 4">
<ctab1 v-show="sindex == 0 && tabs[0].show"></ctab1>
<ctab2 v-show="sindex == 1 && tabs[1].show"></ctab2>
<ctab3 v-show="sindex == 2 && tabs[2].show"></ctab3>
<ctab4 v-show="sindex == 3 && tabs[3].show"></ctab4>
</block>
<block v-else-if="tabs.length >= 5">
<ctab1 v-show="sindex == 0 && tabs[0].show"></ctab1>
<ctab2 v-show="sindex == 1 && tabs[1].show"></ctab2>
<ctab3 v-show="sindex == 2 && tabs[2].show"></ctab3>
<ctab4 v-show="sindex == 3 && tabs[3].show"></ctab4>
<ctab5 v-show="sindex == 4 && tabs[4].show"></ctab5>
</block>
<view class="tabbar">
<view class="tab-item"
v-for="(item,index) in tabs"
:key="item.text"
v-show="item.show"
@click="handleTabClick(index)">
<view class="c-tab-item">
<text :class="'tab-iconfont iconfont '+(item.iconfont)"
:style="'color:'+(sindex == index ? scolor : color)"
v-if="item.iconfont"/>
<image :src="sindex == index ? item.iconSelect : item.icon"
class="tab-icon"
v-else/>
<text class="tab-text"
:style="'color:'+(sindex == index ? scolor : color)">{{item.text}}</text>
<view class="corner"
v-show="item.mark > 0">{{item.mark > 99 ? '99+' : item.mark}}</view>
</view>
</view>
</view>
</block>
</view>
</template>
<script>
//讀取配置
import ctabbar from './ctab-config.js'
export default {
name: "ctab",
data() {
return {
tabs: [],
color: '',
scolor: '',
midBtn: {},
sindex: 0,
floor: -1,//midButton開啟時使用
}
},
mounted() {
let tabbar = ctabbar.tabbar
this.color = tabbar.color
this.scolor = tabbar.selectcolor
if(tabbar.midButton && tabbar.midButton.show && tabbar.tabs.length < 2){
throw new Error('midButton模式開啟,配置tab選項不能少于2個')
}
if(tabbar.midButton && tabbar.midButton.show){
let mlength = tabbar.tabs.length < 4 ? 3 : 5
this.floor = Math.floor(mlength/2)
}
//普通模式,設(shè)置選中的tab項
let tablen = tabbar.tabs.length
if(!tabbar.midButton.show){
if(!tabbar.tabs[0].show){
this.sindex ++
if(tablen >= 2 && !tabbar.tabs[1].show){
this.sindex ++
if(tablen >= 3 && !tabbar.tabs[2].show){
this.sindex ++
if(tablen >= 4 && !tabbar.tabs[3].show){
this.sindex ++
if(tablen >= 5 && !tabbar.tabs[4].show){
throw new Error('tab不能全部隱藏')
}
}
}
}
}
}
if(tabbar.tabs.length <= 5){
this.tabs = tabbar.tabs
}else {
this.tabs = tabbar.tabs.slice(0,5)
}
this.midBtn = tabbar.midButton
},
methods: {
setTheme(color){
this.scolor = color
this.midBtn.background = color
},
//設(shè)置tab隱藏和顯示,midButton模式失效
setTabVisible(index,visible){
if(this.tabs[index]){
this.tabs[index].show = visible
}
},
//設(shè)置角標
setCorner(index,num){
if(this.tabs[index]){
this.tabs[index].mark = num
}
},
handleTabClick(tab){
if(this.midBtn && this.midBtn.show){
if(tab == this.floor){
return
}
}
this.sindex = tab
let rindex = tab
if(this.midBtn && this.midBtn.show){
if(tab > this.floor){
rindex --
}
}
this.$emit('tabClick',rindex)
},
handleMidBtn(){
this.$emit('midClick')
}
}
}
</script>
<style>
/*這里引入字體圖標,如果使用字體圖標的話*/
@import '@/common/font/iconfont.css';
.tabbar {
position: fixed;
z-index: 99;
width: 100%;
height: 100rpx;
background-color: #ffffff;
bottom: 0;
left: 0;
box-shadow: 0rpx 4rpx 8rpx 0rpx rgba(0,0,0,0.5);
border-radius: 0px 0px 0px 0px;
opacity: 1;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
box-sizing: content-box;
}
.tab-item {
flex: 1;
height: 100rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.c-tab-item {
height: 120rpx;
display: flex;
flex-direction: column;
width: 120rpx;
align-items: center;
justify-content: center;
position: relative;
}
.tab-icon {
width: 45rpx;
height: 45rpx;
}
.tab-iconfont {
font-size: 45rpx;
font-weight: bold;
}
.tab-text {
font-size: 26rpx;
color: #333333;
margin-top: 5rpx;
}
.mid-btn {
position: absolute;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
background-color: red;
border-radius: 50%;
}
.mid-text {
font-size: 25rpx;
color: #999999;
}
.corner {
text-align: center;
width: 45rpx;
height: 45rpx;
position: absolute;
background-color: red;
border-radius: 50%;
color: white;
font-size: 20rpx;
font-weight: bold;
top: 5rpx;
right: 0;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
</style>
4、配置文件如下:
var tabbar = {
/*開啟midButton模式時取前兩個或者前四個顯示,其他忽略*/
midButton: {
show: true,//是否是中間凸起模式
width: '153rpx',//不填默認150rpx 中間按鈕大小
iconwidth: '67rpx',//不填默認150rpx 中間圖標大小
iconheight: '60rpx',
offset: '40rpx',//不填默認50rpx
background: '#F7D456',//中間按鈕背景顏色
text: '拍一拍',
textoffset: '50rpx',//不填默認50rpx
showtext: false,
icon: '../../static/tabbar/camera.png'
},
color: '#333333',//未選中顏色
selectcolor: '#F7D456',//選中顏色
/*tabs最多5個,超過5個超過的部分會被忽略,show屬性用來控制tab顯示隱藏,midButton開啟時失效,iconfont優(yōu)先,沒有就使用icon*/
tabs: [{
icon: '../../static/tabbar/main_tab_home_normal.png',
iconSelect: '../../static/tabbar/main_tab_home_select.png',
text: '首頁',
iconfont: '',
show: true,
mark: 0//角標數(shù)量,小于等于0不顯示
}, {
icon: '../../static/tabbar/main_tab_task_normal.png',
iconSelect: '../../static/tabbar/main_tab_task_select.png',
text: '任務(wù)',
iconfont: '',
show: true,
mark: 100
}, {
icon: '../../static/tabbar/main_tab_my_normal.png',
iconSelect: '../../static/tabbar/main_tab_my_select.png',
text: '我的',
iconfont: 'icon-wode',//注意配置字體圖標會優(yōu)先使用字體圖標,這里是示例
show: true,
mark: 9
}]
}
module.exports = {
tabbar
}5、使用示例:
<template>
<ctab @midClick='midClick'
@tabClick='tabClick'
ref="ctab"/>
</template>
<script>
export default {
data() {
return {
}
},
onLoad() {
},
methods: {
//凸起按鈕點擊事件
midClick(){
console.log('midClick')
},
//tab切換點擊事件
tabClick(tab){
console.log('tabClick',tab)
}
}
}
</script>
<style>
page {
width: 100%;
height: 100%;
}
</style>
6、到這里我們自定義tabbar就完成了,通過修改配置文件中的midButton中的show屬性來開啟是否中間按鈕凸起,接下來我們看下效果。
midButton開啟:

普通模式:

再普通模式下,我們可以通過配置或者動態(tài)修改tabs中tab obj中的show屬性來動態(tài)形式和隱藏某個tab,我們這里配置第一個tab為隱藏:
...
tabs: [{
icon: '../../static/tabbar/main_tab_home_normal.png',
iconSelect: '../../static/tabbar/main_tab_home_select.png',
text: '首頁',
iconfont: '',
show: false,//隱藏第一個tab
mark: 0//角標數(shù)量,小于等于0不顯示
}, {
icon: '../../static/tabbar/main_tab_task_normal.png',
iconSelect: '../../static/tabbar/main_tab_task_select.png',
text: '任務(wù)',
iconfont: '',
show: true,
mark: 100
}, {
icon: '../../static/tabbar/main_tab_my_normal.png',
iconSelect: '../../static/tabbar/main_tab_my_select.png',
text: '我的',
iconfont: '',
show: true,
mark: 9
}]
...
效果圖如下:

7、到這里我們的自定義tabbar就完成了,剩下的就是在tab組件中實現(xiàn)我們各個頁面的邏輯。我們通過配置文件可以輕松的使用一個套代碼實現(xiàn)tabbar中間按鈕凸起、數(shù)字角標、動態(tài)隱藏、自定義mask覆蓋tabbar(需要自己控制好層級),字體圖標等功能,并且全端適用。
尾巴
到此這篇關(guān)于uniapp自定義tabbar的文章就介紹到這了,更多相關(guān)uniapp自定義tabbar內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Bootstrap CSS組件之下拉菜單(dropdown)
這篇文章主要為大家詳細介紹了Bootstrap CSS組件之下拉菜單(dropdown),具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-12-12
Layui彈框中數(shù)據(jù)表格中可雙擊選擇一條數(shù)據(jù)的實現(xiàn)
這篇文章主要介紹了Layui彈框中數(shù)據(jù)表格中可雙擊選擇一條數(shù)據(jù)的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05
javascript中導(dǎo)出與導(dǎo)入實現(xiàn)模塊化管理教程
這篇文章主要給大家介紹了關(guān)于javascript中導(dǎo)出與導(dǎo)入實現(xiàn)模塊化管理的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12
window.location和document.location的區(qū)別分析
用戶不能改變document.location(因為這是當前顯示文檔的位置)。但是,可以改變window.location (用其它文檔取代當前文檔)window.location本身也是一個對象,而document.location不是對象2008-12-12
safari,opera嵌入iframe頁面cookie讀取問題解決方法
最近做的合作網(wǎng)站嵌入到對方的iframe中去,在safari,opera和有些版本的搜狗瀏覽器(內(nèi)核版本原因)中不能讀到cookie。2010-06-06
Leaflet?數(shù)據(jù)可視化實現(xiàn)地圖下鉆示例詳解
這篇文章主要為大家介紹了Leaflet數(shù)據(jù)可視化實現(xiàn)地圖下鉆示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-01-01

