微信小程序提供導航相關的API:
使用wx.navigateTo()或者<navigator>組件跳轉的頁面路徑最多只有5層,這些頁面路徑是可以通過wx.navigateBack()API或者左上角返回按鈕按順序返回的。當頁面路徑大于5層時,使用wx.navigateTo()進行下一頁嗎跳轉會拋出錯誤:
navigateTo:fail webview count limit exceed.
但是某些業務場景存在多頁面互動的交互邏輯,遠遠不止5層頁面棧。比如筆者近期參與開發的58到家小程序中存在如下的業務場景:
1、用戶進入小程序,展示首頁;
2、首頁存在一個如下圖的底部導航欄:
用戶點擊“我的”進入個人中心,此時頁面棧為首頁->個人中心,共2層。
3、個人中心頁面存在“我的收入”入口,如下:
4、用戶從個人中心進入我的收入頁面,此時頁面棧為首頁->個人中心->我的收入,共3層;
5、我的收入頁面提供“提現”頁面的入口,如下:
6、用戶進入提現頁面,此時的頁面棧為首頁->個人中心->我的收入->提現,共4層。此時留給我們可支配的頁面棧只剩下一層了。提現流程如下:
提現流程存在多頁面直接的數據共享和交互,如果是常規的webapp,我們通常會考慮使用hash路由或者干脆做成獨立的幾個頁面使用url傳參進行數據通信。但是進入提現頁面之后,我們最多只能再添加一個獨立頁面了。也就是說,銀行列表頁、綁定銀行卡頁和提交成功頁三者只能再使用一個頁面棧(并非一個頁面)承載。如何用僅剩的最后一層頁面棧實現上述復雜的提現流程呢?
首先第一步是將提現行為細分,因為只能再添加一個獨立頁面,所以需要合并一些可在一個頁面完成的行為。上文的流程圖其實遺漏了一個行為:綁定銀行卡頁面點擊銀行卡需要顯示銀行列表頁。也就是允許用戶重新選擇銀行。所以其實整體的提現流程如下:
小程序標題欄左上角返回按鈕的行為(圖中標紅的線條)是返回頁面棧的上一頁面,代碼是無法干預的。
整個流程中必須支持“返回”按鈕正常返回上一頁面的行為有:
要保證第二條“提現頁面進入的銀行列表頁面,正常返回提現頁面”,就必須將銀行列表頁獨立為一個頁面。至此,最后一層頁面棧就定型了。那么剩下的綁定銀行卡和提交成功頁面怎么辦呢?
需要注意的是,銀行列表頁面與綁定銀行卡頁面之間有一個雙向的交互行為,由于最后一個獨立頁面已經確定為銀行列表頁了,所以不得不從中犧牲一定的用戶體驗:綁定銀行卡頁面跳轉到銀行列表頁后不能正常返回。有了這個前提,我們可以把銀行列表和綁定銀行卡兩個邏輯頁面合并為一個實體頁面,通過子路由控制行為展示。
再次回顧上文的交互流程圖還可以得到另外一個信息:提交成功頁面的返回邏輯與提現頁面完全相同。所以,兩者同樣可以合并為一個實體頁面,由子路由控制行為展示。
以第二步的合并規則為準,實體頁面的交互流程如下:
微信小程序的Page是沒有子路由概念的,我們在此討論的子路由其實就是根據Page組件的某個data字段進行不同模板的分發渲染。
首先定義支持的子路由列表:
// 路由列表 const ROUTES = { index: 'index', banklist: 'banklist', setcard: 'setcard', done: 'done' };
我們在代碼上又進一步的融合,將第四層頁面和第五層頁面兩個實體頁面融合為同一個Page組件,通過子路由控制模板的渲染,之所以這樣做有以下幾點考慮:
既然融合為一個Page組件,那么如何實現頁面的跳轉呢?其實很簡單,使用wx.navigateTo()API如下:
wx.navigateTo({ url: './index?route=' + ROUTES.banklist });
上述代碼實現了跳轉到同一Page組件的功能,并且跳轉的頁面會被加入到頁面棧中。
然后在index.wxml中增加路由數據的邏輯判斷分發:
<block wx:if="{{route=='index'}}"> <include src="_part/basic/index.wxml"/> </block> <block wx:if="{{route=='banklist'}}"> <include src="_part/banklist/index.wxml"/> </block> <block wx:if="{{route=='setcard'}}"> <include src="_part/setcard/index.wxml"/> </block> <block wx:if="{{route=='done'}}"> <include src="_part/done/index.wxml"/> </block>
前置頁面進入第四層頁面時默認的是index子路由頁面,有第五層頁面的綁定銀行卡提交后返回第四層頁面時顯示done子路由。這個邏輯中需要注意的是:
也就是說,我們可以再onShow鉤子函數中進行路由的分發。但是如何獲取路由字段呢?大家可能想到的第一個方案就是通過url傳參,可惜這個方案是行不通的。首先,微信小程序官方文檔中關于Page組件鉤子函數的說明,只有onLoad函數可以獲取由url query傳遞的數據,其余的任何鉤子函數都不能獲取;其次,第五層頁面的提交行為返回第四層頁面是由wx.navigateBack()API實現的,這個API的功能是返回頁面棧中的上一層頁面,并不支持指定的修改url,所以url傳參這條路是走不通的。
那么使用cookie是否可行呢?雖然微信小程序不支持cookie,但cookie的理念可以提供給我們解決問題的思路:將數據先儲存在本地,跳轉頁面后獲取本地數據進行相應處理。
有了思路,自然而然地便想到類似cookie的本地storage。
第一步:點擊第五層頁面的提交按鈕后,首先在storage中儲存第四層頁面的route值:
wx.setStorage({ key: 'dj_deposits_route', data: ROUTES.done });
第二步:在第四層頁面的onShow函數內獲取storage中的route數據并賦值給data中的route字段,模板便會同步刷新:
let _route = wx.getStorageSync('dj_deposits_route'); this.setData({ route: _route });
微信小程序的頁面路徑限制為最多5層,多于5層的頁面將不會跳轉并且會拋出錯誤信息。而我們產品的某些業務場景不止存在5層的頁面路徑,在這種情況下,我們不得不犧牲一定的用戶體驗,以保證功能的完整。本文提到的方案是與業務場景息息相關的,只是一家之言,并非最佳實踐。希望能夠給大家一點參考。