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