小程序無限層級路由方案

小程序無限層級路由方案

小程序原生頁面存在層級限制,超過必定層數就會沒法打開新頁面。一開始這個限制爲不超過5層,目前是不超過10層。git

這個限制對於體量較大的小程序來講,挺難受的。特別是只能打開5層那會兒,業務流程很容易一不當心就超了,好比:首頁-搜索結果頁-商品詳情頁-聊天頁-下單頁-地址選擇頁-...;更有訪問迴路防不勝防,好比:商品詳情頁-查看更多頁-商品詳情頁-查看更多頁-...、商品詳情頁-聊天頁-我的主頁-商品詳情頁-聊天頁-我的主頁-商品詳情頁-...、諸如此類。即便後來放寬至了10層,仍是很容易遭遇層級溢出。github

一種處理思路是調整交互路徑,嚴格控制層級數量。可是這種處理方案,一則不少時候會犧牲用戶體驗,好比爲避免我的主頁和商品詳情頁的訪問迴路,要麼不能在我的主頁中訪問用戶商品,要麼不能在商品詳情頁中訪問賣家主頁,要麼訪問時須要替換當前不能返回繼續瀏覽,無論怎麼取捨都會犧牲某些用戶的瀏覽訴求;二則維護成本特別高,業務邏輯愈來愈複雜,交互路徑愈來愈發散,路徑的統一梳理和規劃就會愈來愈困難,並且管理過程對業務不透明,業務方在設計需求時要受到交互路徑的種種限制,甚至一個需求的交互調整極可能無心中形成另外一個需求層級溢出,維護成本高且不斷膨脹。小程序

於是本文考慮並實現了另外一種處理思路:在小程序中支持不限層級的路由過程。segmentfault

策略

  • 修改小程序默認導航行爲,自行維護完整歷史記錄
  • 頁面層級小於等於10時,導航行爲與原生導航行爲一致
  • 請求打開第11層及以上時,邏輯層級記錄完整歷史,實際層級每次都是直接將第10層替換爲目標頁面
  • 返回時,邏輯層級相應回退;若回退後邏輯層級大於等於10,則實際層級將第10層替換爲目標頁面,不然實際層級回退到相應頁面
  • demo:
邏輯層級 1 - 2 - ... - 8 - 9 - 10
  實際層級 1 - 2 - ... - 8 - 9 - 10
  
  打開
  
  邏輯層級 1 - 2 - ... - 8 - 9 - 10 - 11
  實際層級 1 - 2 - ... - 8 - 9 - 11
  
  打開,打開,打開
  
  邏輯層級 1 - 2 - ... - 8 - 9 - 10 - 11 - 12 - 13 - 14
  實際層級 1 - 2 - ... - 8 - 9 - 14
  
  返回
  
  邏輯層級 1 - 2 - ... - 8 - 9 - 10 - 11 - 12 - 13
  實際層級 1 - 2 - ... - 8 - 9 - 13
  
  返回,返回,返回
  
  邏輯層級 1 - 2 - ... - 8 - 9 - 10
  實際層級 1 - 2 - ... - 8 - 9 - 10
  
  返回
  
  邏輯層級 1 - 2 - ... - 8 - 9
  實際層級 1 - 2 - ... - 8 - 9

實現

轉轉 實現了上述策略,並提供開源使用,地址:https://github.com/zhuanzhuanfe/fancy-mini,歡迎使用或參閱。微信

主要難點及實現方案:併發

  • 如何接管路由過程
    • 要求全部頁面不使用<navigator>元素,統一使用js觸發跳轉
    • 要求全部頁面不直接調用wx.navigateTo、wx.redirectTo等路由相關接口,統一改用模塊封裝的相應接口
  • 如何監聽返回行爲
    • 統一監聽頁面的onUnload函數,結合路由過程判斷是否用戶返回
  • 如何兼容系統交互
    • 問題:系統交互會跳出正常路由流程,而且難以接管或監控,如:用戶點擊右上角返回主頁按鈕、用戶切後臺後又從其它入口進入、用戶強制關閉小程序進程等
    • 處理:引入校訂機制,在合適的時機根據系統路由棧對自行維護的路由棧進行校訂。這樣能夠保證10層之內路由正確性。系統交互可能是回到第1層,會被成功校訂。
  • 如何避免/兼容代碼疏漏
    • 問題:接管&監聽過程要求全部頁面遵循一些編碼約束,如何保證這些約束切實全面生效;萬一有頁面未遵循約束,可否依然保證健壯性
    • 處理1:編寫並配置相應eslint規則,保證約束被切實遵循
    • 處理2:上一條中的校訂機制,保證即便有代碼疏漏,在10層內也會被校訂;10層外可能會影響返回邏輯正確性,但通常不會形成頁面功能問題。
  • 如何進行狀態恢復
    • 問題:返回後邏輯層級大於等於10時,實際是在第10層從新載入目標頁面;用戶在前一頁面的表單輸入等狀態信息並不會像系統返回同樣正常保留
    • 處理:在合適的時機存儲頁面的data,返回時予以恢復

成本

  • 接入成本
    • 須要引入並配置路由模塊
    • 須要檢查並修改項目中全部頁面跳轉過程,統一使用模塊封裝的接口
    • 須要統一監聽全部頁面的onUnload函數
  • 維護成本
    • 新增頁面跳轉過程,需統一使用模塊封裝的接口
    • 新增頁面onUnload函數需接入統一監聽
  • 性能成本
    • 模塊執行邏輯相對簡單,內存開銷相對較小,頁面性能暫未發現明顯損耗

收益

  • 無限層級
    • 避免複雜/循環訪問致使頁面沒法打開
    • 能夠放心地向用戶提供適合的訪問入口,沒必要過度擔憂路徑限制
  • 徹底的路由管控能力
    • 能夠徹底監控路由過程並實現或引入一些附加功能
    • 附加功能:實例覆蓋自動恢復
      • 問題:wepy框架存在單實例問題,同一路徑頁面被打開兩次時,其數據會相互影響,如:詳情頁A - 詳情頁B - 返回A,點擊查看大圖 - B的圖片(而不是A的圖片)
        詳見issue:兩級頁面爲同一路由時,後者數據覆蓋前者
      • 策略:返回時,若判斷目標頁面數據已被覆蓋,則自動予以恢復
      • 引入:參見模塊使用說明
    • 附加功能: 免併發
      • 問題:用戶連續快速點擊多個/屢次按鈕時,會一次性打開多個窗口,一則形成層級膨脹,二則影響瀏覽體驗
      • 策略:第一次點擊形成的跳轉完成以前無視後續點擊產生的跳轉請求
      • 引入:參見模塊使用說明
    • 附加功能:數據預先加載
      • 問題:小程序的page1跳轉到page2,到page2的onLoad是存在一個300ms ~ 400ms的延時的,在page2的onLoad中才開始獲取數據會浪費這個延時
      • 策略:在 page1 中預先拿取數據,而後在 page2 中直接使用數據;wepy框架對此有良好的實現,參見WePY 在小程序性能調優上作出的探究
      • 引入:參見模塊使用說明

效果

無限層級路由方案已在 轉轉二手交易網 小程序中應用了很長一段時間,歡迎體驗:
微信-我-錢包-轉轉二手框架

無限層級路由方案已被抽離封裝成獨立開源模塊,歡迎直接使用:https://github.com/zhuanzhuanfe/fancy-miniide


update:函數

  • 這是否是與小程序政策相背離呢?
    其實,我的感受小程序不是不想支持無限層級,而是不方便支持。
    實踐發現,打開一個新的空頁面,內存消耗會增長30M左右,複雜頁面甚至可能消耗幾百M內存,層級一多,很容易黑屏。因此官方不方便支持無限層級。
    相比之下,轉轉這個策略內存開銷基本能夠忽略不計,是一個比較合適的折中/保底方案。
    交互設計上仍是應該儘可能簡化,儘可能扁平,層級不宜過深;可是也不宜過度掣肘。本方案主要仍是做爲一個基礎保障,並不能所以就不注重交互設計。性能

  • 爲啥還要保留1-9層,直接全部交互都在第一層或第二層處理會有啥問題?
    由於原生層級的返回體驗會比較好。
    原生頁面返回時數據、交互狀態、頁面元素等都仍是駐留在內存的,返回過程很流暢;
    無限層級模擬返回則是在最後一層從新載入目標頁面,元素須要從新渲染,數據須要從新設置,返回體驗相對有所犧牲。
    因此無限層級主要仍是做爲功能保障,並不宜直接取代原生層級。

  • 「對於這種多頁面來回跳轉,建議優化設計,就單單用戶須要返回這個操做,會返回到死」 頁面訪問迴路是很難徹底避免的,無限層級方案能夠起到基礎保障的做用。 「返回到死」問題,咱們另有策略:當層級>=8時,頁面右下角會出現一個快捷導航條,能夠馬上reLaunch到首頁等高頻頁面。

相關文章
相關標籤/搜索