微信小程序頁面5層限制的一種解決方案

1、背景android

不少開發者在面對小程序的五層頁面限制時,心裏大概是崩潰的。
使用wx.navigateTo()或<navigator>組件(open-type=navigate時)跳轉的頁面路勁最多隻有5層,這些頁面路徑能夠經過wx.navigateBack() API或者左上角返回按鈕順序返回。當頁面路徑大於5層時,使用wx.navigateTo()跳轉下一頁不會有任何動靜,頁面既不跳轉也不會報錯(這就尷尬了,若是沒有細看開發文檔,還覺得是本身代碼寫錯了呢)。[注:開發工具和ios都不會報錯,沒有驗證android的表現]
可是,有時候業務場景存在多頁面交互的狀況,遠遠不止5層頁面,這時候如何輕鬆處理頁面跳轉就成了一個不得不考慮的問題。

2、頁面棧&小程序導航API接口ios

微信小程序中的頁面導航API有3個:wx.navigateTo、wx.redirectTo、wx.navigateBack。wx.navigateTo和wx.redirectTo打開新的頁面,wx.navigateBack用於返回上一個頁面(棧裏的頁面)。

 這3個頁面API的區別在於:
  • navigateTo 不會將舊頁面出棧;
  • redirectTo 會將舊頁面出棧,再將須要跳轉到的頁面入棧;
  • navigateBack 則是將頁面棧最後一個元素出棧,所以倒數第二個元素會成爲最後一個元素,即變成「當前頁面」。

一、wx.navigateTo接口與頁面棧示意圖
圖片描述json

當棧滿了(5層)以後,再調用wx.navigateTo()跳轉任何頁面,都不會成功。
特別注意的是,調用兩次wx.navigateTo('頁面B');wx.navigateTo('頁面B');,那麼棧裏存在兩個頁面B(或者說兩個頁面B的實例),以下圖。

圖片描述

二、wx.redirectTo接口與頁面棧示意圖
圖片描述小程序

三、wx.navigateBack微信小程序

這個比較容易理解,就是棧裏的頁面一個一個出棧。當最後一個頁面(首頁A)出棧後,也就退出了小程序。
在新版庫中,給wx.navigateBack添加了一個參數delta,用於決定須要返回幾層頁面;若是delta大於等於現有頁面數(也就是棧裏的頁面數),則返回到首頁。

圖片描述

四、頁面棧與wx.navigateBack
圖片描述緩存

在此突出wx.navigateBack(OBJECT)和getCurrentPages()接口,由於本文提出的應對頁面棧5層限制的方案正是充分利用這兩個接口的結果。

3、一種能夠解決問題的方案
一、方案的提出微信

由以上的對導航接口和頁面棧的分析能夠知道兩點:
(1)調用兩次wx.navigateTo('頁面B'),那麼棧裏存在兩個頁面B(或者說兩個頁面B的實例)。但其實棧裏沒有必要保留兩個頁面B實例
(2)wx.navigateBack的參數delta能夠返回棧裏的指定頁面,其中頁面信息能夠由getCurrentPages()接口獲得

據此,提出以下一種解決方案
(1)自定義頁面跳轉方式
(2)當頁面棧裏已經存在要跳轉的目標頁面A,那麼使用wx.navigateBack({delta: xx})返回到此頁面A,{xx=getCurrentPages().length - 目標頁面A在棧裏的index - 1}
(3)若是頁面棧尚未要跳轉的目標頁面A
        a、若頁面棧已經已滿(length>=5),那麼使用wx.redirectTo(頁面A);
        b、不然,使用wx.navigateTo(頁面A)
(4)頁面間數據採用緩存傳遞

二、方案的實現app

/*
* desc:
*  一、若是目標頁面已經在棧中,那麼wx.navigateBack({delta: xx})到目標頁面
*  二、若是目標頁面不在棧中,
*    (1)若是棧大小<5,那麼wx.navigateTo(目標頁面)
*    (2)不然,wx.redirectTo(目標頁面)
*  三、全部頁面間的數據傳輸,經過緩存攜帶
*  四、跳轉目標頁,用goPage()
*  五、在目標頁,經過inPage()接收數據。接收後,數據會被刪除
*/
Nav = {
    MAX_VALUE: 5, //頁面棧最多5層
    /*
     * desc: 跳轉頁面
     * param:
     *  obj: {
     *    url: ''  //頁面在app.json中的路徑,路徑前不要加'/'斜槓(也能夠加,作了兼容)
     *    data: {}  //須要攜帶的參數,統一經過緩存攜帶
     *  }
     */
    goPage: function(obj) {
        var pages = getCurrentPages(),  //頁面棧
            len = pages.length,
            dlt = '',
            target = '/' + obj.url.replace(/^\//, ''), //若是有,將第一個‘/’去掉,而後再補上(開發者習慣不一樣,有些人會給url加/,有些則忘了,兼容處理
            navigation_key = target.replace(/\//g, '_'); //存儲數據的下標,每一個頁面由本身的存儲key,保證了頁面間數據不會相互污染
        //查找目標頁在頁面棧的位置
        for (var i = 0; i < len; i++) {
            if (pages[i].route == target) { //
                dlt = i + 1; //目標頁在棧中的位置
                break;
            }
        }
        //保存數據
        //因爲navigateBack()回到指定頁面,不會從新執行onLoad事件,因此加個標兵。
        //只有在isLoad = true;時,纔會接收參數並執行類onLoad事件
        var nData = Object.assign({ referer: pages[len - 1].route, _is_load: true }, obj.data || {});
        wx.setStorageSync(navigation_key, JSON.stringify(nData));
        if (!dlt) { //頁面不在棧中
            if (len < this.MAX_VALUE) {
                wx.navigateTo({
                    url: target
                });
            } else {
                wx.redirectTo({
                    url: target
                });
            }
        } else {
            wx.navigateBack({
                delta: len - dlt
            });
        }
    },
    /*
     * desc:在目標頁接收數據
     * param:
     *    myOnLoad:回調方法,因爲經過緩存傳遞數據,頁面onLoad沒辦法接收,因此要自定義回調
     */
    inPage: function(myOnLoad) {
        var pages = getCurrentPages();
        var navigation_key = pages[pages.length - 1].route.replace(/\//g, '_');
        //從其餘頁面跳轉過來的,那麼isLoad確定爲true,由於goPage中設置了。若是是用戶點擊左上角後退的,那麼isLoad=false,由於下面設置了
        //獲取數據
        try {
            var raw = wx.getStorageSync(navigation_key);
            var options = JSON.parse(raw);
            if(options._is_load && myOnLoad) {  //用戶點擊左上角後退時,不會執行myOnLoad,由於此時_is_load是undefined
              myOnLoad(options);
            }
            wx.setStorage({ //清除數據
                key: navigation_key,
                data: ''  //這以後,_is_load是undefined了
            });
        } catch (e) {
            
        }
    }
};
採用以上方案後,就能夠專心寫代碼邏輯了,不須要再擔憂頁面層級無心間超過5層致使沒法跳轉的問題。

4、最完美的解決方案工具

以上方案是完美的嗎?
想一想,若是通過屢次(超過5次)跳轉,而後點擊左上角後退會出現什麼狀況?是否是中間通過的一些頁面不見了(早已經出棧了)。用戶通常的預期是,我點擊跳轉屢次,後退應該原路返回,即從哪裏來的回到哪裏去&怎麼走過來的就怎麼走回去。
但這個問題顯然是沒法解決的,由於,一旦頁面超過了5層,總有頁面得出棧,「原路返回」已經失去了條件。
其實,對於頁面5層限制的問題,官方文檔已經給出了完美的解決方案:

圖片描述

相關文章
相關標籤/搜索