1. 程式人生 > >再談小程序自定義底部導航

再談小程序自定義底部導航

hone const 版本 css custom 打開 單獨 自定義樣式 ram

小程序自定義tabBar再探索

前言

最近有很多微信開發者朋友在QQ上加我好友,忽然意識到大家對微信自定義底部導航欄需求還是挺大的,故而再次整理下底部導航欄組件開發思路。和之前的文章還是有些區別,並且底部導航欄組件增加新的特性以及一些優化開發體驗的騷操作。

技術選型

與之前不同,現在我們有兩種方法實現自定義底部導航欄,因為小程序在2.5.0開始支持自定義底部導航欄了戳此處看文檔,所以我們現在的可選方案為:

  • 通過HideTabBar接口hack底部導航欄
  • 通過小程序支持配置實現底部導航欄

下面根據兩種方式都講講

通過HideTabBar接口hack底部導航欄

實現思路

首先我們先了解下微信的路由api和微信的路由機制,微信一共提供了5個路由api:wx.navigateTo

wx.redirectTowx.switchTabwx.navigateBackwx.reLaunch,具體文檔位於https://developers.weixin.qq.com/miniprogram/dev/api/ui-navigate.html。

技術分享圖片

其中我們用哪個呢?很顯然wx.switchTab很合我們的口味,因為他的切換效果是沒有推入推出動畫的,更符合我們的習慣,那使用他的前提是我們需要在app.json文件中配置tabBar屬性,而只要一配置了tabBar屬性,系統原生的導航欄就出現了,幸好微信有一個隱藏原生導航欄的api:wx.hideTabBar。看到這裏相信聰明的同學已經知道了實現思路,就是隱藏掉原生的然後自己去實現一個導航欄貼在最下面。

使用方法

源碼地址

  • 微信小程序代碼片段
  • github

本次代碼拷貝之後可以直接使用,具體操作如下

  1. 復制components/custom-tab-bar文件夾到你的項目
  2. 在app.json中設置usingComponents對象技術分享圖片

  3. 在tab頁面的wxml最後追加<custom-tab-bar></custom-tab-bar>

即可觀察效果

支持的特性

  • 無需額外配置,甚至不用傳參,自動讀取app.jsontabBar的配置
  • 使用wx.showTabBarRedDot方法可以設置紅點
  • 可以自定義樣式,擺脫微信限制(如borderStyle僅支持black/white的限制)
  • 可以定制個性化邏輯
  • 兼容iphoneX,底部自動留空

關鍵代碼介紹

tabBar配置的獲取

看過之間博客的同學知道,之前是需要一個額外的route.js文件的,來獲取tabBar的配置,原因是小程序js無法讀取json文件。隨著知(sao)識(cao zuo)掌握增多,發現了更加方便的辦法:我們可以通過__wxConfig全局對象的tabBar屬性去查看app.json設置。所以我們在組件中直接這樣定義:

const fixListConfig = function(item, index) {
  const result = {}; // 使用新對象,類似淺拷貝
  result.pagePath = "/" + item.pagePath.replace(/.html$/g, "");
  result.iconPath = item.iconData
    ? "data:image/png;base64," + item.iconData
    : "/" + item.iconPath;
  result.selectedIconPath = item.selectedIconData
    ? "data:image/png;base64," + item.selectedIconData
    : "/" + item.selectedIconPath;
  result.idx = index;
  result.redDot = false;
  result.text = item.text;
  return result;
};  
const _tabBar = __wxConfig.tabBar;

Component({
  data: {
    activeIdx: -1,
    config: _tabBar,
    list: _tabBar.list.map(fixListConfig)
  },
});

其中list就是我們tab頁面列表,tabBar裏面還包括了我們定義的一些樣式,比如selectColor之類的,因為格式並不是直接拿來就能用,所以我們用map對數據進行了修改和淺拷貝。

此處還有一個坑,部分真機上小程序配置中的圖標會變成base64格式的,所以需要做兼容。

上面代碼不是難點,關鍵在於__wxConfig對象,大家可以在微信開發工具控制臺執行this.__wxConfig看看裏面的內容,相信能對你有所啟發。
技術分享圖片

當前頁的判斷

相信大家都用過getCurrentPages()這個全局函數,我們也是通過它來獲取當前頁面的路由然後將其標記為active狀態。本著自己的事情自己做的原則,我利用自定義組件的pageLifetimes功能,實現了內部判斷當前頁,具體代碼如下:

pageLifetimes: {
    show() {
      const pages = getCurrentPages();
      const page = pages[pages.length - 1];
      const route = page.__route__;
      const idx = this.data.list.find(item => item.pagePath === `/${route}`)
        .idx;
      if (this.data.activeIdx !== idx) {
        this.setData({
          activeIdx: idx
        });
      }
    }
}

註意pageLifetimes特性在基礎庫2.2.3以上支持,目前沒什麽問題,其實外面傳值寫死也是ok的,畢竟每個頁面是一個單獨的組件。

使用css兼容iPhone X(強烈建議了解)

此處一需一行代碼

.tab-bar{
    padding-bottom: env(safe-area-inset-bottom);
}

這個方法不光可用於小程序,也可用於移動端,網上有很多介紹他的文章,比如網頁適配 iPhoneX,就是這麽簡單

修改wx接口註入自己的代碼邏輯

上面特性中提到了,我們可以使用wx.showTabBarRedDot方法設置我們的redDot,也可以打開上面的小程序微碼查看效果。這個是利用Object.defineProperty方法實現的,具體代碼可以看custom-tab-bar/extraFun.js文件查看。這塊就不再詳述了,大家想了解的可以直接閱讀源碼,如果有疑問可以單獨聯系我。

通過小程序支持配置實現底部導航欄

現在,我們來聊聊為什麽不用小程序支持的配置方法實現底部導航欄。

使用方法

現在我們根據文檔進行改造,在app.jsontabBar對象中增加"custom":true,並在根目錄下增加custom-tab-bar/index組件。之後的開發就和上面差不多了,我們寫組件實現期望的效果。

兩者的區別

為了描述方便,我們將之前提到的方法稱為方法一,小程序配置的稱之為方法二。方法一的組件是在page裏面的,方法二的組件是和page並列的關系,如圖所示:
技術分享圖片
這個對我們有什麽影響嗎,就我目前觀察,有幾個問題

  • 某些情況下會引起bug,當我們打開一個非tab頁面的時候,還是會顯示底部導航欄。(最嚴重問題,會有bug)
  • 無法使用全局定義的樣式,哪怕組件激活了addGlobalClass選項之後(不了解addGlobalClass的同學見文檔:使組件接受全局樣式)
  • 需要基礎庫>=2.5.0,有部分用戶無法覆蓋。當前版本分布情況

總結

最後還是感謝大家能堅持讀完,本人作為一個理科生,文筆太差,有許多想法表達不出來,真是吃了沒文化的虧。文中介紹的兩種方法,我目前還是只會考慮第一種,以後會一直觀望微信配置法,相信當它完善的那天我會毫不猶豫的使用,畢竟跟著標準才能走的更遠。如果對本代碼或在開發過程中遇到什麽問題,歡迎與我交流858582381~

另外,下一步打算分享自定義頭部標題欄,不知道大家對此是否期待。
技術分享圖片

再談小程序自定義底部導航