小程序无限层级路由方案

小程序无限层级路由方案

小程序原生页面存在层级限制,超过必定层数就会没法打开新页面。一开始这个限制为不超过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到首页等高频页面。

相关文章
相关标签/搜索