看官方demo的小伙伴知道,自定义tabbar需要在小程序根目录底下建一个名叫custom-tab-bar的组件(我有试过,如果放在components目录里面小程序会识别不了),目前我自己实现的效果是:通过在配置可以切换tab,也可以点击tab后重定向到新页面,支持隐藏tabbar,同时也可以显示右上角文本和小红点。
官方demo里面用的是cover-view,我改成view,因为如果页面有弹窗的话我希望可以盖住tabbar
总结一下有以下注意点:
1、tabbar组件的目录命名需要是custom-tab-bar
2、app.json增加自定义tabbar配置
3、wx.navigateTo不允许跳转到tabb页面
4、进入tab页面时,需要调用tabbar.js手动切换tab
效果图:
可以扫码体验
代码目录如下:
代码如下:
app.json增加自定义tabbar配置
"tabBar": {
"custom": true,
"color": "#7A7E83",
"selectedColor": "#3cc51f",
"borderStyle": "black",
"backgroundColor": "#ffffff",
"list": [
{
"pagePath": "pages/love/love",
"text": "首页"
},
{
"pagePath": "pages/tabbar/empty",
"text": "礼物说"
},
{
"pagePath": "pages/tabbar/empty",
"text": "恋人圈"
},
{
"pagePath": "pages/me/me",
"text": "我"
}
]
},
自定义tabbar组件代码如下
index.js
//api.js是我自己对微信接口的一些封装
const api = require('../utils/api.js');
//获取应用实例
const app = getApp();
Component({
data: {
isPhoneX: false,
selected: 0,
hide: false,
list: [{
showRedDot: false,
showBadge: false,
badgeText: "",
pagePath: "/pages/love/love",
iconPath: "/images/tabbar/home.png",
selectedIconPath: "/images/tabbar/home-select.png",
text: "首页"
}, {
showRedDot: false,
showBadge: false,
badgeText: "",
pagePath: "/pages/tabbar/empty",
navigatePath: "/pages/gifts/giftList",
iconPath: "/images/tabbar/gift.png",
selectedIconPath: "/images/tabbar/gift-select.png",
text: "礼物说",
hideTabBar: true
}, {
showRedDot: false,
showBadge: false,
badgeText: "",
pagePath: "/pages/tabbar/empty",
navigatePath: "/pages/moments/moments",
iconPath: "/images/tabbar/lover-circle.png",
selectedIconPath: "/images/tabbar/lover-circle-select.png",
text: "恋人圈",
hideTabBar: true
}, {
showRedDot: false,
showBadge: false,
badgeText: "",
pagePath: "/pages/me/me",
iconPath: "/images/tabbar/me.png",
selectedIconPath: "/images/tabbar/me-select.png",
text: "我"
}]
},
ready() {
// console.error("custom-tab-bar ready");
this.setData({
isPhoneX: app.globalData.device.isPhoneX
})
},
methods: {
switchTab(e) {
const data = e.currentTarget.dataset;
console.log("tabBar参数:", data);
api.vibrateShort();
if (data.hideTabBar) {
api.navigateTo(data.navigatePath);
} else {
/*this.setData({
selected: data.index
}, function () {
wx.switchTab({url: data.path});
});*/
/**
* 改为直接跳转页面,
* 因为发现如果先设置selected的话,
* 对应tab图标会先选中,然后页面再跳转,
* 会出现图标变成未选中然后马上选中的过程
*/
wx.switchTab({url: data.path});
}
},
/**
* 显示tabbar
* @param e
*/
showTab(e){
this.setData({
hide: false
}, function () {
console.log("showTab执行完毕");
});
},
/**
* 隐藏tabbar
* @param e
*/
hideTab(e){
this.setData({
hide: true
}, function () {
console.log("hideTab执行完毕");
});
},
/**
* 显示小红点
* @param index
*/
showRedDot(index, success, fail) {
try {
const list = this.data.list;
list[index].showRedDot = true;
this.setData({
list
}, function () {
typeof success == 'function' && success();
})
} catch (e) {
typeof fail == 'function' && fail();
}
},
/**
* 隐藏小红点
* @param index
*/
hideRedDot(index, success, fail) {
try {
const list = this.data.list;
list[index].showRedDot = false;
this.setData({
list
}, function () {
typeof success == 'function' && success();
})
} catch (e) {
typeof fail == 'function' && fail();
}
},
/**
* 显示tab右上角文本
* @param index
* @param text
*/
showBadge(index, text, success, fail) {
try {
const list = this.data.list;
Object.assign(list[index], {showBadge: true, badgeText: text});
this.setData({
list
}, function () {
typeof success == 'function' && success();
})
} catch (e) {
typeof fail == 'function' && fail();
}
},
/**
* 隐藏tab右上角文本
* @param index
*/
hideBadge(index, success, fail) {
try {
const list = this.data.list;
Object.assign(list[index], {showBadge: false, badgeText: ""});
this.setData({
list
}, function () {
typeof success == 'function' && success();
})
} catch (e) {
typeof fail == 'function' && fail();
}
}
}
});
index.html
<view class="footer-tool-bar flex-center {{isPhoneX? 'phx_68':''}}" hidden="{{hide}}">
<view class="tab flex-full {{selected === index ? 'focus':''}}"
wx:for="{{list}}"
wx:key="index"
data-path="{{item.pagePath}}"
data-index="{{index}}"
data-navigate-path="{{item.navigatePath}}"
data-hide-tab-bar="{{item.hideTabBar}}"
data-open-ext-mini-program="{{item.openExtMiniProgram}}"
data-ext-mini-program-app-id="{{item.extMiniProgramAppId}}"
bindtap="switchTab">
<view class="text">
<view class="dot" wx:if="{{item.showRedDot}}"></view>
<view class="badge" wx:if="{{item.showBadge}}">{{item.badgeText}}</view>
<image class="icon" src="{{item.selectedIconPath}}" hidden="{{selected !== index}}"></image>
<image class="icon" src="{{item.iconPath}}" hidden="{{selected === index}}"></image>
</view>
</view>
</view>
index.json
{
"component": true,
"usingComponents": {}
}
index.wxss
@import "/app.wxss";
.footer-tool-bar{
background-color: #fff;
height: 100rpx;
width: 100%;
position: fixed;
bottom: 0;
z-index: 100;
text-align: center;
font-size: 24rpx;
transition: transform .3s;
border-radius: 30rpx 30rpx 0 0;
/*padding-bottom: env(safe-area-inset-bottom);*/
box-shadow:0rpx 0rpx 18rpx 8rpx rgba(212, 210, 211, 0.35);
}
.footer-tool-bar .tab{
color: #242424;
height: 100%;
line-height: 100rpx;
}
.footer-tool-bar .focus{
color: #f96e49;
font-weight: 500;
}
.footer-tool-bar .icon{
width: 44rpx;
height: 44rpx;
margin: 18rpx auto;
}
.footer-tool-bar .text{
line-height: 80rpx;
height: 80rpx;
position: relative;
display: inline-block;
padding: 0rpx 40rpx;
box-sizing: border-box;
margin: 10rpx auto;
}
.footer-tool-bar .dot{
position: absolute;
top: 16rpx;
right: 16rpx;
height: 16rpx;
width: 16rpx;
border-radius: 50%;
background-color: #f45551;
}
.footer-tool-bar .badge{
position: absolute;
top: 8rpx;
right: 8rpx;
height: 30rpx;
width: 30rpx;
line-height: 30rpx;
border-radius: 50%;
background-color: #f45551;
color: #fff;
text-align: center;
font-size: 20rpx;
font-weight: 450;
}
.hide{
transform: translateY(100%);
}
app.wxss(这里的样式文件是我用来存放一些公共样式)
/**app.wxss**/
page {
background-color: #f5f5f5;
height: 100%;
-webkit-overflow-scrolling: touch;
}
.container {
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
}
.blur {
filter: blur(80rpx);
opacity: 0.65;
}
.flex-center {
display: flex;
align-items: center;
justify-content: center;
}
.flex-column {
display: flex;
/*垂直居中*/
align-items: center;
/*水平居中*/
justify-content: center;
flex-direction: column;
}
.flex-start-horizontal{
display: flex;
justify-content: flex-start;
}
.flex-end-horizontal{
display: flex;
justify-content: flex-end;
}
.flex-start-vertical{
display: flex;
align-items: flex-start;
}
.flex-end-vertical{
display: flex;
align-items: flex-end;
}
.flex-wrap {
display: flex;
flex-wrap: wrap;
}
.flex-full {
flex: 1;
}
.reset-btn:after {
border: none;
}
.reset-btn {
background-color: #ffffff;
border-radius: 0;
margin: 0;
padding: 0;
overflow: auto;
}
.loading{
opacity: 0;
transition: opacity 1s;
}
.load-over{
opacity: 1;
}
.phx_68{
padding-bottom: 68rpx;
}
.phx_34{
padding-bottom: 34rpx;
}
另外我还对tabbar的操作做了简单的封装:
tabbar.js
const api = require('/api.js');
/**
* 切换tab
* @param me
* @param index
*/
const switchTab = function (me, index) {
if (typeof me.getTabBar === 'function' && me.getTabBar()) {
console.log("切换tab:", index);
me.getTabBar().setData({
selected: index
})
}
};
/**
* 显示 tabBar 某一项的右上角的红点
* @param me
* @param index
*/
const showRedDot = function (me, index, success, fail) {
if (typeof me.getTabBar === 'function' && me.getTabBar()) {
me.getTabBar().showRedDot(index, success, fail);
}
};
/**
* 隐藏 tabBar 某一项的右上角的红点
* @param me
* @param index
*/
const hideRedDot = function (me, index, success, fail) {
if (typeof me.getTabBar === 'function' && me.getTabBar()) {
me.getTabBar().hideRedDot(index, success, fail);
}
};
/**
* 显示tab右上角文本
* @param me
* @param index
* @param text
*/
const showBadge = function (me, index, text, success, fail) {
if (typeof me.getTabBar === 'function' && me.getTabBar()) {
me.getTabBar().showBadge(index, text, success, fail);
}
};
/**
* 隐藏tab右上角文本
* @param me
* @param index
*/
const hideBadge = function (me, index, success, fail) {
if (typeof me.getTabBar === 'function' && me.getTabBar()) {
me.getTabBar().hideBadge(index, success, fail);
}
};
/**
* 显示tabbar
* @param me
* @param success
*/
const showTab = function(me, success){
if (typeof me.getTabBar === 'function' && me.getTabBar()) {
me.getTabBar().showTab(success);
}
};
/**
* 隐藏tabbar
* @param me
* @param success
*/
const hideTab = function(me, success){
if (typeof me.getTabBar === 'function' && me.getTabBar()) {
me.getTabBar().hideTab(success);
}
};
module.exports = {
switchTab, showRedDot, hideRedDot, showBadge, hideBadge, showTab, hideTab
};
最后,进入到tab对应页面的时候要手动调用一下swichTab接口,然tabbar聚焦到当前tab
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
tabbar.switchTab(this, this.data.tabIndex);//tabIndex是当前tab的索引
}
建议结尾放个代码片段。方便直接查看效果。
https://developers.weixin.qq.com/miniprogram/dev/devtools/minicode.html