在開始以前呢,先提示一下你們,這裏所說的自定義導航指的是底部的tabbar!不要問我爲何,我也不知道。vue
其實我我的是不推薦自定義tabbar的,但爲何我仍是這麼去作了呢?主要緣由是咱們的業務須要根據客羣的不一樣展現不一樣的tabbar,若是用原生的tabbar是沒法實現的。所以咱們最後決定經過自定義的方式來實現。不想看文字也沒事,看一下個人示意圖你就知道需求了...╮(╯_╰)╭json
是否是秒懂!😎小程序
自定義導航最大的優點就是自定義,這不是廢話嗎...😂我總結了如下優點供你們參考:數組
自定義導航的優點仁者見仁智者見智。可能由於業務的不一樣,所體現的優點也不同,我就不在這裏掰扯了。緩存
說了這些優點,其實自定義導航的劣勢也比較明顯:bash
由於tabbar是一個比較獨立的模塊,因此能夠寫成組件的形式,這樣子也方便維護。引入組件方法要是不熟悉的話,你們能夠看官方的文檔。自定義組件微信
這裏我把組件命名爲nav,目錄結構以下:app
能夠看到組件模塊的目錄結構和普通的page頁面沒什麼區別,固然page頁面須要在app.json裏邊進行引入,可是組件的話是不須要的。異步
接下來,咱們須要在組件的json文件中配置一下:xss
{
"component": true,
"usingComponents": {}
}
複製代碼
其餘的就不須要再進行配置了。固然,假如你的組件裏邊須要引入其餘的組件,能夠用一樣的方式,而且在"usingComponents": {}
裏邊引入就行。
接下來就是wxml文件的書寫。這個頁面的話就和page頁面同樣就好了。這裏不須要考慮裏邊的節點數,由於最後小程序會把他們再封裝到一個根節點上,因此你們沒必要要再本身再添加一個根節點。
其餘的話,有一個地方可能須要和你們提醒一下,記得給iPhoneX作一下兼容!這裏個人tabbar用的是fixed的佈局方式,因此可能會遮住一些元素。
<view class="nav-placeholder" style="padding-bottom: {{isIpx ? 68 : 0}}rpx;"></view>
複製代碼
我解決的方案如上,採用的是一個空白的元素進行佔位。
引用組件的時候須要在目標頁面的json文件中聲明一下:
"usingComponents": {
"x-nav":"../../",
}
複製代碼
而後在模板中直接引用就好了:
<x-nav show="{{true}}" cartcount="{{cartcount}}" catchtouchmove="ture"></x-nav>
複製代碼
這裏的樣式就不要再具體說明了,由於組件的存在因此裏邊的類名不會被污染,你們放心的使用,你們能夠在裏邊加各類動畫,好比下邊這樣:
這個只是一個思路,要是我真這麼設計,估計明天就會由於鞋帶是蝴蝶結的被開除。大家可讓設計作一些高大上的東西出來。
若是你非要用外部的樣式的話也能夠,可是你本身須要注意類名命名的問題,能夠經過聲明options
來實現:
options:{
addGlobalClass: true
},
複製代碼
js的結構可能會有一些不同,由於是組件,因此再也不是經過page({})
這樣子的方式去建立,而會改爲Component({})
的方式。
其餘的寫法和vue就比較像了。
props
就變成了properties
,格式以下:
properties: {
val1: {
type: Boolean,
value: false,
observer: function(newVal, oldVal) {
console.log(newVal, oldVal);
}
},
val2: {
type: String,
value: '0',
observer: function(newVal, oldVal) {
console.log(newVal, oldVal);
}
},
...
},
複製代碼
properties
中假如你傳入的值可能會是不一樣類型的你能夠換成optionalTypes
,這個是支持多類型的
data的話就不必細說了,小程序的組件裏邊依然支持getApp()
的方法,假如你有什麼方法寫在app.js中也是能夠直接調用的。
在這裏邊我會用到show()
方法,組件中使用onShow()
這種帶on的生命週期是有一些特別的,以下:
pageLifetimes:{
show(){
consolelog('show');
},
hide(){
consolelog('hide');
},
resize(){
consolelog('hide');
},
},
複製代碼
不帶on的話是寫在另一個對象中的lifetimes:{}
:
lifetimes: {
attached() {
// 在組件實例進入頁面節點樹時執行
},
detached() {
// 在組件實例被從頁面節點樹移除時執行
},
created() {
// 在組件實例剛剛被建立的時候
},
ready() {
// 在組件在視圖層佈局完成後執行
},
moved() {
// 在組件實例被移動到節點樹另外一個位置時執行
},
error() {
// 每當組件方法拋出錯誤時執行
}
},
複製代碼
這裏可能會有同窗有疑問這個lifetimes裏的方法爲何能夠寫在外邊,其實寫在外邊的是舊式的定義方式,能夠保持對 <2.2.3> 版本基礎庫的兼容。
其餘的地方有一個navList:[]
這個就是導航tab的list了,格式的話,推薦你們能夠模仿原生的格式:
navList: [
{
name:'***', //nav的名稱
url:'****', //跳轉的地址
actived:true, //是否選中狀態
nomalImg:'***', //不被選中時的icon
activedImg:'***', //被選中的icon
type:'***' //導航類型
},
{
name:'***',
url:'***',
actived:false,
nomalImg:'***',
activedImg:'***',
type:'***'
},
{
name:'***',
url:'***',
actived:false,
nomalImg:'***',
activedImg:'***',
type:'***'
}
],
複製代碼
這裏的話你們能夠優化一下,由於當時寫的比較急,再總結的時候發現好多地方能夠優化。好比這個navList
你們能夠改成對象的模式,由於在getCurrentPages()
中的路徑其實也是/pages/....
這樣子的格式,你們能夠把路徑做爲key,這樣就不須要每次change的時候都去遍歷一次數組,媽耶,當時我怎麼就沒這麼寫...😭
還有一點思路能夠供給你們做爲參考,由於咱們在切換tab的時候須要把actived
的狀態進行修改,這個修改咱們能夠不用去過多的去考慮切換的過程,由於原生的切換是使用wx.switchTab
的方式進行切換,咱們自定義導航的話也能夠模仿這個方式去作,咱們能夠用wx.redirectTo
來代替,由於用的是redirect,因此咱們在判斷路由的時候比較方便,直接取路由中的第一個來進行判斷就好了。
其實說到路由棧,有一個比較麻煩的地方就是,當這個tab頁面變成一個常規的頁面時(就是能夠經過navigate的方式訪問),咱們的訪問路徑就會複雜起來,舉個例子吧:
假如你經過點擊tab進行切換頁面的時候,這個是正常狀況,可是假如你從別的頁面訪問的時候這個路由的長度可能就會大於1,這個時候你就須要對路由進行更加細緻的檢查了。
其餘的話,我遇到的問題就是背景中提到的根據客羣的不一樣展現不一樣的tabbar。
這個的問題點在於,咱們獲取用戶客羣信息的時候是個異步的過程,當請求回來的時候會有一個比較明顯的變換過程,可能導航就會從三個變成四個,這個的話,目前的個人方案沒有徹底避免,由於我不可能等到請求回來的時候再顯示導航條吧,因此我會把用戶第一次請求的結果記錄下來,以後的話會優先取緩存中的數據,這樣除了用戶第一次回變換一次,以後的話就不會出現閃爍的狀況。
你們在可使用小程序原生的tabbar的時候就用原生的,由於原生的體驗上會更好一些。固然,若是不得不用自定義導航的時候不如就好好設計一下,充分發揮自定義導航的優點。要是你們有什麼別的想法,歡迎你們在底下留言,同時也歡迎你們加我微信交流:zyf348519452,交個朋友也很好啊😎