背景
在做快狗叫車小程式時,關於預設導航欄,我們遇到了以下的問題:
- Android、IOS手機對於頁面title的展示不一致,安卓title的顯示不居中
- 頁面的title只支援純文字級別的樣式控制,不能夠做更豐富的title效果
- 左上角的事件無法監聽、定製
- 路由導航單一,只能夠返回上一頁,深層級頁面的返回不夠友好
我們希望的是:在各個機型頁面上title一致性 & 個性化展示、取得左上角點選事件控制權及深層級頁面的一鍵返回
實現
step1 自定義
第一步 取得導航欄的控制權
小程式支援自定義導航欄,只需要在app.json
檔案中,window
項中配置
"navigationStyle": "custom"
複製程式碼
這樣微信就放開了導航欄的控制權,只保留右上角的膠囊。
頁面會從視窗的頂部開始渲染,如圖
接下來,我們要做的就是實現一個導航欄元件,把它放置在頁面原來的預設導航欄的位置,內容什麼的完全由開發者自己定製。
step2 功能點
第二步 梳理導航欄的功能點
- 導航欄高度(各個機型動態適配)
- 導航欄內容定製
- 所有機型title居中顯示(自己佈局實現)
首頁
導航欄左上角顯示個人中心、中部title使用個性圖示巢狀頁面
左上角顯示返回上一頁
+回到首頁
按鈕非常規首頁
左上角顯示回到首頁
按鈕
導航欄高度 包含兩個部分:工具欄和title欄, 工具欄的高度一般是固定的20px,title欄的高度需要計算
導航欄內容的定製,需要識別當前頁面的性質,根據不同的頁面展示不同的內容,可以通過獲取當前的頁面路由棧來判定當前的頁面性質
step3 導航欄元件基本結構
目前快狗叫車小程式的基本結構
// navBar.wxml
<cover-view class='place-holder'></cover-view>
<cover-view class='nav-bar'>
<cover-view class='tool-bar' style='height: 20px'></cover-view>
<cover-view class='title-bar'>
<cover-view class='left-cell'>
// scene0 常規首頁 個人中心按鈕
// scene1 非常規首頁 回首頁按鈕
// scene2 巢狀頁 返回上一頁按鈕 + 回首頁按鈕
</cover-view>
<cover-view class='center-cell'>
// scene0 常規首頁 個性化title
// scene1 其他頁 正常title
</cover-view>
<cover-view class='right-cell'>
// 佔位用的
</cover-view>
</cover-view>
</cover-view>
複製程式碼
Tips:
- 元件內多了一個佔位的place-holder塊,是因為某些頁面有類似滾動列表的需求,要保證導航欄始終在視窗的頂部的話,需要使用定位,定位之後脫離文件流,在最初的時候需要佔位塊保證後續的頁面內容不會被導航欄遮擋
- 使用
cover-view
佈局是因為快狗的業務中有類似map
的原生元件,使用view
的話有被遮擋的風險
step4 高度計算
需要計算title-bar
的高度
在 預設導航欄 & 無底部tab欄 的情況下,使用wx.getSystemInfoSync
獲取手機資訊,可以看到兩項資訊:
screenHeight
螢幕高度,單位pxwindowHeight
可使用視窗高度,單位px
這種情況下,二者的差值就是預設的導航欄的高度, 但是在設定了"navigationStyle": "custom"
之後,二者的值是一樣的了,因此導航欄的高度我們需要使用統計的經驗值。
根據統計,得到如下的結果:
{
'iPhone': 64,
'iPhoneX': 88,
'Android': 68,
'samsung': 72
}
複製程式碼
工具欄的高度可根據wx.getSystemInfoSync
返回值中的statusBarHeight
獲取。
至此,我們得到了導航欄的相關的高度值
// 導航欄總高度 & 佔位塊高度
placeHoder = totalBar = {
'iPhone': 64,
'iPhoneX': 88,
'Android': 68,
'samsung': 72
}
// 時間、訊號等工具欄的高度
toolBar = systermInfo.statusBarHeight
// 頁面title欄的高度
titleBar = totalBar - toolBar
複製程式碼
step5 內容定製
在元件的生命週期函式attached
中,我們可以獲取當前的頁面路由棧
let pages = getCurrentPages()
let current_page = pages[pages.length - 1].route
const NORMAL_ENTRY = '常規的入口頁路徑'
// scene 0 常規入口頁 個性化title、個人中心
pages.length === 1 && current_page === NORMAL_ENTRY
// scene 1 非常規入口頁 回首頁
pages.length === 1 && current_page !== NORMAL_ENTRY
// scene 2 巢狀頁面 返回 + 回首頁
pages.length > 1
複製程式碼
根據不同的條件,展示不同的內容
最終效果
scene 0 常規首頁
scene 1 非常規首頁
scene 2 巢狀頁
目前在生產環境99%的機型中,都可以完美的執行。
寫在最後
- 自定義導航欄是全域性生效的,一旦設定,各個原生小程式頁面都需要引入
- 目前微信版本7+支援了針對特定頁面的自定義導航欄,可以根據需要個性化定製
- 自定義導航欄在web-view頁面不會起效
- 有嘗試把導航欄做成外掛,但是遇到在外掛元件中無法獲取頁面路由棧的問題,因此沒有成功