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

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

特別注意這里的tab組件命名一定要符合easycom規(guī)范,不然可能會(huì)引起組件引用錯(cuò)誤。
這里示例一個(gè)ctab1寫(xiě)法:
<template>
<view style="width: 750rpx;height: 300rpx;background-color: red;">
首頁(yè)
</view>
</template>
<script>
export default {
name: "ctab1",
data() {
return {};
},
mounted() {},
methods: {}
}
</script>
<style>
</style>
3、tabbar組件ctab.vue實(shí)現(xiàn),這里就直接上代碼了,直接copy就能使用,關(guān)鍵地方已加上注釋
<template>
<view>
<!--中間按鈕凸起模式-->
<block v-if="midBtn && midBtn.show">
<!--凸起模式最多展示四個(gè)-->
<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個(gè)或者5個(gè)-->
<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開(kāi)啟時(shí)使用
}
},
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模式開(kāi)啟,配置tab選項(xiàng)不能少于2個(gè)')
}
if(tabbar.midButton && tabbar.midButton.show){
let mlength = tabbar.tabs.length < 4 ? 3 : 5
this.floor = Math.floor(mlength/2)
}
//普通模式,設(shè)置選中的tab項(xiàng)
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è)置角標(biāo)
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>
/*這里引入字體圖標(biāo),如果使用字體圖標(biāo)的話*/
@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 = {
/*開(kāi)啟midButton模式時(shí)取前兩個(gè)或者前四個(gè)顯示,其他忽略*/
midButton: {
show: true,//是否是中間凸起模式
width: '153rpx',//不填默認(rèn)150rpx 中間按鈕大小
iconwidth: '67rpx',//不填默認(rèn)150rpx 中間圖標(biāo)大小
iconheight: '60rpx',
offset: '40rpx',//不填默認(rèn)50rpx
background: '#F7D456',//中間按鈕背景顏色
text: '拍一拍',
textoffset: '50rpx',//不填默認(rèn)50rpx
showtext: false,
icon: '../../static/tabbar/camera.png'
},
color: '#333333',//未選中顏色
selectcolor: '#F7D456',//選中顏色
/*tabs最多5個(gè),超過(guò)5個(gè)超過(guò)的部分會(huì)被忽略,show屬性用來(lái)控制tab顯示隱藏,midButton開(kāi)啟時(shí)失效,iconfont優(yōu)先,沒(méi)有就使用icon*/
tabs: [{
icon: '../../static/tabbar/main_tab_home_normal.png',
iconSelect: '../../static/tabbar/main_tab_home_select.png',
text: '首頁(yè)',
iconfont: '',
show: true,
mark: 0//角標(biāo)數(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',//注意配置字體圖標(biāo)會(huì)優(yōu)先使用字體圖標(biāo),這里是示例
show: true,
mark: 9
}]
}
module.exports = {
tabbar
}5、使用示例:
<template>
<ctab @midClick='midClick'
@tabClick='tabClick'
ref="ctab"/>
</template>
<script>
export default {
data() {
return {
}
},
onLoad() {
},
methods: {
//凸起按鈕點(diǎn)擊事件
midClick(){
console.log('midClick')
},
//tab切換點(diǎn)擊事件
tabClick(tab){
console.log('tabClick',tab)
}
}
}
</script>
<style>
page {
width: 100%;
height: 100%;
}
</style>
6、到這里我們自定義tabbar就完成了,通過(guò)修改配置文件中的midButton中的show屬性來(lái)開(kāi)啟是否中間按鈕凸起,接下來(lái)我們看下效果。
midButton開(kāi)啟:

普通模式:

再普通模式下,我們可以通過(guò)配置或者動(dòng)態(tài)修改tabs中tab obj中的show屬性來(lái)動(dòng)態(tài)形式和隱藏某個(gè)tab,我們這里配置第一個(gè)tab為隱藏:
...
tabs: [{
icon: '../../static/tabbar/main_tab_home_normal.png',
iconSelect: '../../static/tabbar/main_tab_home_select.png',
text: '首頁(yè)',
iconfont: '',
show: false,//隱藏第一個(gè)tab
mark: 0//角標(biāo)數(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組件中實(shí)現(xiàn)我們各個(gè)頁(yè)面的邏輯。我們通過(guò)配置文件可以輕松的使用一個(gè)套代碼實(shí)現(xiàn)tabbar中間按鈕凸起、數(shù)字角標(biāo)、動(dòng)態(tài)隱藏、自定義mask覆蓋tabbar(需要自己控制好層級(jí)),字體圖標(biāo)等功能,并且全端適用。
尾巴
到此這篇關(guān)于uniapp自定義tabbar的文章就介紹到這了,更多相關(guān)uniapp自定義tabbar內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- uniapp小程序底部tabbar圖標(biāo)大小設(shè)置辦法
- uniapp原生tabbar設(shè)置并添加數(shù)字角標(biāo)或小紅點(diǎn)提示功能
- uniapp小程序自定義tabbar以及初次加載閃屏解決方法
- 小程序自定義tabbar導(dǎo)航欄及動(dòng)態(tài)控制tabbar功能實(shí)現(xiàn)方法(uniapp)
- uniapp小程序配置tabbar底部導(dǎo)航欄實(shí)戰(zhàn)指南
- uniapp微信小程序底部動(dòng)態(tài)tabBar的解決方案(自定義tabBar導(dǎo)航)
- uniapp如何使用uv-popup彈出框隱藏底部導(dǎo)航tabbar
相關(guān)文章
Bootstrap CSS組件之下拉菜單(dropdown)
這篇文章主要為大家詳細(xì)介紹了Bootstrap CSS組件之下拉菜單(dropdown),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-12-12
Layui彈框中數(shù)據(jù)表格中可雙擊選擇一條數(shù)據(jù)的實(shí)現(xiàn)
這篇文章主要介紹了Layui彈框中數(shù)據(jù)表格中可雙擊選擇一條數(shù)據(jù)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05
JavaScript模塊化開(kāi)發(fā)之SeaJS
SeaJS是一個(gè)遵循CommonJS規(guī)范的JavaScript模塊加載框架,可以實(shí)現(xiàn)JavaScript的模塊化開(kāi)發(fā)及加載機(jī)制,本文給大家介紹JavaScript模塊化開(kāi)發(fā)之SeaJS,需要的朋友參考下2015-12-12
基于JavaScript打造一款桌面級(jí)便簽系統(tǒng)
本文將用html,css和JavaScript實(shí)現(xiàn)一個(gè)簡(jiǎn)單的便簽系統(tǒng)。除非手動(dòng)清空便簽,否則便簽會(huì)一直保留,非常方便。感興趣的小伙伴可以跟隨小編一起動(dòng)手試一試2022-02-02
javascript中導(dǎo)出與導(dǎo)入實(shí)現(xiàn)模塊化管理教程
這篇文章主要給大家介紹了關(guān)于javascript中導(dǎo)出與導(dǎo)入實(shí)現(xiàn)模塊化管理的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12
window.location和document.location的區(qū)別分析
用戶(hù)不能改變document.location(因?yàn)檫@是當(dāng)前顯示文檔的位置)。但是,可以改變window.location (用其它文檔取代當(dāng)前文檔)window.location本身也是一個(gè)對(duì)象,而document.location不是對(duì)象2008-12-12
safari,opera嵌入iframe頁(yè)面cookie讀取問(wèn)題解決方法
最近做的合作網(wǎng)站嵌入到對(duì)方的iframe中去,在safari,opera和有些版本的搜狗瀏覽器(內(nèi)核版本原因)中不能讀到cookie。2010-06-06
Leaflet?數(shù)據(jù)可視化實(shí)現(xiàn)地圖下鉆示例詳解
這篇文章主要為大家介紹了Leaflet數(shù)據(jù)可視化實(shí)現(xiàn)地圖下鉆示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01

