小程序(一)自定义导航栏

274 阅读4分钟

我正在参加「创意开发 投稿大赛」详情请看:掘金创意开发大赛来了!

前言

小程序做久了,难免会遇到一些奇奇怪怪的产品需求,比如让你想办法去掉胶囊栏,比如在小程序里运行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的配置

40605f2d6e9e5870e07d50249d5418f.jpg

首先在小程序项目的组件库中新建 自定义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 全局开启