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