再談小程序自定義底部導航
小程序自定義tabBar再探索
前言
最近有很多微信開發者朋友在QQ上加我好友,忽然意識到大家對微信自定義底部導航欄需求還是挺大的,故而再次整理下底部導航欄組件開發思路。和之前的文章還是有些區別,並且底部導航欄組件增加新的特性以及一些優化開發體驗的騷操作。
技術選型
與之前不同,現在我們有兩種方法實現自定義底部導航欄,因為小程序在2.5.0開始支持自定義底部導航欄了戳此處看文檔,所以我們現在的可選方案為:
- 通過
HideTabBar
接口hack底部導航欄 - 通過小程序支持配置實現底部導航欄
下面根據兩種方式都講講
通過HideTabBar
接口hack底部導航欄
實現思路
首先我們先了解下微信的路由api和微信的路由機制,微信一共提供了5個路由api:wx.navigateTo
wx.redirectTo
、wx.switchTab
、wx.navigateBack
、wx.reLaunch
,具體文檔位於https://developers.weixin.qq.com/miniprogram/dev/api/ui-navigate.html。
其中我們用哪個呢?很顯然wx.switchTab
很合我們的口味,因為他的切換效果是沒有推入推出動畫的,更符合我們的習慣,那使用他的前提是我們需要在app.json
文件中配置tabBar
屬性,而只要一配置了tabBar
屬性,系統原生的導航欄就出現了,幸好微信有一個隱藏原生導航欄的api:wx.hideTabBar。看到這裏相信聰明的同學已經知道了實現思路,就是隱藏掉原生的然後自己去實現一個導航欄貼在最下面。
使用方法
源碼地址
- 微信小程序代碼片段
- github
本次代碼拷貝之後可以直接使用,具體操作如下
- 復制components/custom-tab-bar文件夾到你的項目
在app.json中設置
usingComponents
對象在tab頁面的wxml最後追加
<custom-tab-bar></custom-tab-bar>
即可觀察效果
支持的特性
- 無需額外配置,甚至不用傳參,自動讀取
app.json
中tabBar
的配置 - 使用
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.json
的tabBar
對象中增加"custom":true
,並在根目錄下增加custom-tab-bar/index
組件。之後的開發就和上面差不多了,我們寫組件實現期望的效果。
兩者的區別
為了描述方便,我們將之前提到的方法稱為方法一,小程序配置的稱之為方法二。方法一的組件是在page裏面的,方法二的組件是和page並列的關系,如圖所示:
這個對我們有什麽影響嗎,就我目前觀察,有幾個問題
- 某些情況下會引起bug,當我們打開一個非tab頁面的時候,還是會顯示底部導航欄。(最嚴重問題,會有bug)
- 無法使用全局定義的樣式,哪怕組件激活了
addGlobalClass
選項之後(不了解addGlobalClass
的同學見文檔:使組件接受全局樣式) - 需要基礎庫>=2.5.0,有部分用戶無法覆蓋。當前版本分布情況
總結
最後還是感謝大家能堅持讀完,本人作為一個理科生,文筆太差,有許多想法表達不出來,真是吃了沒文化的虧。文中介紹的兩種方法,我目前還是只會考慮第一種,以後會一直觀望微信配置法,相信當它完善的那天我會毫不猶豫的使用,畢竟跟著標準才能走的更遠。如果對本代碼或在開發過程中遇到什麽問題,歡迎與我交流858582381~
另外,下一步打算分享自定義頭部標題欄,不知道大家對此是否期待。
再談小程序自定義底部導航