我正在参加「创意开发 投稿大赛」详情请看:掘金创意开发大赛来了!
前言
小程序做久了,难免会遇到一些奇奇怪怪的产品需求,比如让你想办法去掉胶囊栏,比如在小程序里运行jar包、微信小程序使用支付宝支付、在小程序里执行JavaScript解释器(7月份刚被微信全面禁止)等等。除了这些需求之外,可能还会遇到一些特俗的样式需求,最常见的莫过于自定义底部tabbar。
一般来说,小程序底部的tabbar通常是通过app.json里配置的,并且这一块是具有原生特性的功能区域,不存在同层渲染等等莫名其妙的Bug,tabbar这片区域是固有区域,整个页面的内容区是无法覆盖、定位在tabbar之上的。因为内容区在tabbar坐标之。由于官方的限制,tabbar的icon只能是本地图片,无法使用svg、并且平常用于展示购物车数量的右上角指示器,也默认只能是红色,无法更改。但是基于一些业务场景,可能需要动态展示不同的tabbar导航栏,那么就需要我们手动自定义配置了。
自定义Tabbar的配置
需要特别说明,小程序原生的tabbar是不受同层渲染影响的,但是自定义tabbar会受影响,因为原生组件的层级是最高的,所以页面中的其他组件无论设置 z-index 为多少,都无法盖在原生组件上。
小程序常见的原生组件有:camera、video、map、live-player、live-pusher、textarea、input;由于原生组件脱离在 WebView 渲染流程外,因此在使用时有以下限制:
-
原生组件的层级是最高的,所以页面中的其他组件无论设置 z-index 为多少,都无法覆盖在原生组件上。
-
原生组件的事件监听不能使用 bind:eventname 的写法,只支持 bindeventname。原生组件也不支持 catch 和 capture 的事件绑定方式。
而自定义组件非原生组件,在渲染方面需要注意以下。
1:在app.json的配置
首先在小程序项目的组件库中新建 自定义tabbar组件,比如名叫custom-tab-bar;
在 app.json 中的 tabBar 项指定 custom 字段,在所有用到自定义tabbar的 json文件里需声明 usingComponents 项,也可以在 app.json 全局开启。
{
"tabBar": {
"custom": true,
"color": "#000000",
"selectedColor": "#000000",
"backgroundColor": "#000000",
"list": [{
"pagePath": "page/component/index",
"text": "组件"
}, {
"pagePath": "page/API/index",
"text": "接口"
}]
},
"usingComponents": {}
}
2:在自定义组件中index.wxml内容如下:
<cover-view class="tab-bar" id="tab">
<cover-view class="tab-bar-border"></cover-view>
<cover-view wx:for="{{list}}" wx:key="index" class="tab-bar-item" data-path="{{item.pagePath}}" data-index="{{index}}" bindtap="switchTab">
<cover-image class="icon" src="{{selected == index ? item.selectedIconPath : item.iconPath}}"></cover-image>
<cover-view class="txt" style="color: {{selected == index ? selectedColor : color}}">{{item.text}}</cover-view>
</cover-view>
</cover-view>
3:在组件的index.js中:
const App = getApp();
Component({
data: {
selected: 0,
color: "#999",
selectedColor: "#000",
list: [
{
"pagePath": "/pages/index/index",
"text": "首页",
"iconPath": '../imgs/tab1.png',
"selectedIconPath": '../imgs/se_tab1.png',
"type": "0",
},
{
"pagePath": "/pages/giftCard/giftCard",
"text": "商城",
"iconPath": '../imgs/tab2.png',
"selectedIconPath": '../imgs/se_tab2.png',
"type": "1"
},
{
"pagePath": "/pages/webrtc/index",
"text": "直播有礼",
"iconPath": '../imgs/tab1.png',
"selectedIconPath": '../imgs/se_tab1.png',
"type": "2",
},
{
"pagePath": "/pages/cart/cart",
"text": "购物车",
"iconPath": '../imgs/tab4.png',
"selectedIconPath": '../imgs/se_tab4.png',
"type": "4"
},
{
"pagePath": "/pages/myOrder/myOrder",
"text": "我的",
"iconPath": '../imgs/tab3.png',
"selectedIconPath": '../imgs/se_tab3.png',
"type": "5"
}]
},
attached() {},
methods: {}
})
4:给自定义组件添加一些样式index.wxss:
.tab-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 48px;
background: white;
display: flex;
padding-bottom: env(safe-area-inset-bottom);
}
.tab-bar-border {
background-color: rgba(0, 0, 0, 0.33);
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 1px;
transform: scaleY(0.5);
}
.tab-bar-item {
flex: 1;
text-align: center;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.icon {
width: 27px;
height: 27px;
}
.txt {
font-size: 10px;
}
5:这样配置后,你真正的TabBar页面就可以直接自己使用这个自定义的TabBar文件了,不需要你去写任何引用的标签
注意:每个在每一个tab页面的onshow方法里写上如下代码:
-
这个是为了防止跳转页面后选中的效果丢失;
-
selected是写选中第几个按钮的索引。
if (typeof that.getTabBar === 'function' && that.getTabBar()) {
that.getTabBar().setData({
selected: 0
})
}
缺点
-
点击底部按钮的时候在模拟器上页面会闪,真机上正常;
-
效率相比于原生的会差一点,但是体验上基本感觉不出来。
优点
-
自定义样式,可实现一些其他业务逻辑的判断,比如判断用户会员等级展示不同的tabbar;触发授权等等,条件判断跳转拦截;
-
可使用原生TabBar跳转方式跳转wx.switchTab;
-
可以在非TabBar页面进入这个自定义TabBar。
注意点
此外,如果你想实现业务弹窗组件从底部弹出,是否影响自定义tabbar的展示,需要自行决定好用view还是cover-view。官方demo里面用的是cover-view,我改成view,因为如果页面有弹窗的话我希望可以盖住tabbar。
-
tabbar组件的目录命名需要是custom-tab-bar
-
wx.navigateTo不允许跳转到tabbar页面(一直都是不允许)
-
进入tab页面时,需要调用tabbar.js手动切换tabbar
-
自定义tabBar是需要配置tabBar中 "cust": true ,同时其余 tabBar 相关配置也补充完整例如list不能省略,并且要跟自定义tabbar中的list一致,否则会出现报错
-
所有 tab 页的 json 里需声明 usingComponents 项,也可以在 app.json 全局开启