订阅本栏目 RSS您所在的位置: 深山工作室 > uni-app > 正文

微信小程序页面栈超过【10层】之后无法打开其他页面原因

2021/8/14 10:28:43 字体: 浏览 741

使用getCurrentPages可以获取当前加载中所有的页面对象的一个数组,数组最后一个就是当前页面。

var pages = getCurrentPages() //获取加载的页面

var currentPage = pages[pages.length-1] //获取当前页面的对象

var url = currentPage.route //当前页面url

var options = currentPage.options //如果要获取url中所带的参数可以查看options





微信小程序路由跳转有个隐藏的坑,就是 wx.navigateTo打开新页面,最多只能打开10个,超过10个之后就没反应,控制台也不会报错。


方案一:简单粗暴…navigateTo不行,用redirectTo

小程序路由跳转的方式有五种,分别是wx.navigateTo(打开新页面,新页面入栈)、wx.redirectTo(重定向,当前页面出栈,新页面入栈)、wx.navigateBack(返回,页面不断出栈,直到目标返回页)、wx.switchTab(切换tab页面,页面全部出栈,只留下新的 Tab 页面)、wx.reLaunch(页面全部出栈,只留下新的页面)


由此产生了第一种方式,当页面栈超过 10 时,直接用redirectTo。


但这样太粗暴了,显然很多场景是需要保留访问过的页面的,由此有了方案一的升级版。


方案一升级版:根据页面栈决定当前跳转方式

每次跳转先去页面栈中查找目标页面是否已经访问过,如果访问过则用wx.navigateBack返回,如果没有访问过则判断页面栈中是否已经有10个页面,有则用wx.redirectTo,没有则navigateTo


class RouteMap {

  constructor(opt={}) {

    this.MAX_DEEP = opt.MAX_DEEP || 10

    this.IS_AUTO_BACK = opt.IS_AUTO_BACK || true

    this.PAGE_STACk = getCurrentPages()

  }

 

  _findPageInHistory(path) {

    const { PAGE_STACk } = this

    let delta = -1

    for (let i = 0; i < PAGE_STACk.length; i++) {

      if (PAGE_STACk[i].route === path) {

        delta = i + 1 // 目标页在栈中的位置

        break

      }

    }

    return delta

  }

  _dataToUrlQuery(data={}) {

    let query = '?';

    const prop in data) {

      if (data.hasOwnProperty(prop)) {

        const value = data[prop];

        query += `${prop}=${value}&`

      }

    }

    return query.replace(/&$/,'');

  }

  goPage(opt) {

    if (!opt) return new Error('缺少参数')

    if (opt && !opt.path) '缺少跳转目标path')

    const pageStackLen = PAGE_STACk.length

    let { path,data } = opt

    let delta = this._findPageInHistory(path)

    path = '/' + path.replace(/^\//,0);">'') + this._dataToUrlQuery(data)

 

    if (delta > -1 && this.IS_AUTO_BACK) {

      // 如果有目标页已经是被访问过的

      const backPage = PAGE_STACk[pageStackLen - delta]

      backPage.setData({data});

      wx.navigateBack({

        delta: pageStackLen - delta

      })

    } else {

      if (pageStackLen < this.MAX_DEEP) {

        wx.navigateTo({

          url: path

        })

      } else {

        wx.redirectTo({

          url: path

        })

      }

    }

  }

 

}

module.exports = RouteMap

但是这样依然有问题,页面传参数变得无法统一,而且明明是前进页面,用户使用的时候很可能看着就是返回了几个页面。


方案二:在小程序页面栈之外维护多一个自己的逻辑栈

9层(含9层)以内时:走小程序自己的历史栈就ok了,跳转时候更新一下逻辑栈,这没啥可说的

从9层跳转10层:需要把第9层重定向到中转页,再由中转页跳转到10层

10层以后跳转:在navigateTo方法中处理,到10层之后,再跳转就第10层页面一直做redirectTo(重定向)操作了

10层以上返回:会返回到中转页,由中转页判断,具体返回到哪个页面,然后navigateTo(跳转)过去

从10层返回到9层:返回到中转页,将中转页redirectTo(重定向)到第9层页面

9层内的返回:直接返回就好了,返回时候不会更新逻辑栈,但没有关系,因为只有中转页才会用到逻辑栈

逻辑栈更新机制:

跳转、返回中转页时更新

navigateTo时更新

redirectTo时更新

reLaunch时更新

navigateBack时更新

图示:


用户操作

小程序历史栈

js逻辑栈:自行维护的js路由栈

“中”表示中转页

“1 2 3 4 5 6 7 8 9 A B C”表示不同的页面路径

用户操作 小程序历史栈 js逻辑栈 后续操作

1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 跳转页面9

1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 跳转页面A

1 2 3 4 5 6 7 8 9 A 1 2 3 4 5 6 7 8 中 A 1 2 3 4 5 6 7 8 9 A 跳转页面B

1 2 3 4 5 6 7 8 9 A B 1 2 3 4 5 6 7 8 中 B 1 2 3 4 5 6 7 8 9 A B 跳转页面C

1 2 3 4 5 6 7 8 9 A B C 1 2 3 4 5 6 7 8 中 C 1 2 3 4 5 6 7 8 9 A B C 返回

1 2 3 4 5 6 7 8 9 A B 1 2 3 4 5 6 7 8 中 B 1 2 3 4 5 6 7 8 9 A B 返回

1 2 3 4 5 6 7 8 9 A 1 2 3 4 5 6 7 8 中 A 1 2 3 4 5 6 7 8 9 A 返回

1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 返回(逻辑栈不更新)

1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 9 返回(逻辑栈不更新)

1 2 3 4 5 6 7 1 2 3 4 5 6 7 1 2 3 4 5 6 7 8 9 返回(逻辑栈不更新)

1 2 3 4 5 6 1 2 3 4 5 6 1 2 3 4 5 6 7 8 9 返回(逻辑栈不更新)

1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 6 7 8 9 跳转页面6

1 2 3 4 5 6 1 2 3 4 5 6 1 2 3 4 5 6 跳转页面7

1 2 3 4 5 6 7 1 2 3 4 5 6 7 1 2 3 4 5 6 7 ...

到这里细心的读者可能已经发现:


之前跳转操作和10层以上的返回操作都会更新逻辑栈,到了10层以内的返回操作就不会更新逻辑栈了。


原因:


这块也是我们对原有方案的主要改造点。因为到了10层以内,所有的返回和跳转都由微信系统历史栈接管了。


我们只要保证用户在通过api进行跳转操作时更新就可以了。而且,自己维护的逻辑路由栈实际上只有中转页才会用到。


这样也就不用在每个页面都要注册onUnload钩子去实时更新返回时的路由信息了。把更新路由信息的逻辑都放到了api调用这一层。业务开发时完全不用关心。


示意代码

lib/navigator/Navigator.js (自己封装的跳转方法, History.js代码省略了)


...

import History from '@/lib/navigator/History'

const MAX_LEVEL = 10 // 小程序支持打开的页面层数

export default class Navigator {

  // 中转页面路径

  static curtainPage = '/pages/curtain/curtain/main'

  // 最大页数

  static maxLevel = MAX_LEVEL

  // 逻辑栈

  static _history = new History({

    routes: [{ url: '' }],

    correctLevel: MAX_LEVEL - 2

  })

  

  ...

  

  /**

   * 打开新页面

   * @param {Object} route 页面配置,格式同wx.navigateTo

   */

  @makeMutex({ namespace: globalStore, mutexId: 'navigate' }) // 避免跳转相关函数并发执行

  static async navigateTo (route) {

    console.log('[Navigator] navigateTo:', route)

    // 更新逻辑栈

    Navigator._history.open({ url: route.url })

 

    let curPages = getCurrentPages()

    // 小于倒数第二层时,直接打开

    if (curPages.length < MAX_LEVEL - 1) {

      await Navigator._secretOpen(route) // 就是调用wx.navigateTo

    // 倒数第二层打开最后一层

    } else if (curPages.length === MAX_LEVEL - 1) {

      const url = URL.setParam(Navigator.curtainPage, { url: route.url })

      await Navigator._secretReplace({ url })  // wx.redirectTo 到中转页,再由中转页跳转到第10层页面

    // 已经达到最大层数,直接最后一层重定向

    } else {

      await Navigator._secretReplace(route)    // wx.redirectTo 第10层页面直接重定向

    }

  }

  

  /**

   * 完整历史记录

   * @return {Array}

   */

  static get history () {

    return Navigator._history.routes

  }

  

  /**

   * 更新路由

   * @param {Object} config 自定义配置,可配置项参见 _config 相关字段及注释

   */

  static updateRoutes (routes = []) {

    this._history._routes = routes

  }

  

  ...

}

中转页代码 /pages/curtain/curtain/index.vue


<template>

  <div class="main"></div>

</template>

<script>

import Navigator from '@/lib/navigate/Navigator'

// query参数

let opts = null

// 是否为返回操作

let isBack = false

 

export default {

  onLoad (options) {

    // 缓存参数

    opts = options

    // 执行onLoad生命周期,认为是跳转或者重定向操作

    isBack = false

  },

  onShow () {

    // 跳转、重定向操作时,逻辑栈的状态会在跳转函数里更新

    if (!isBack) {

      const url = decodeURIComponent(opts.url)

      // 再返回时认为是返回操作

      isBack = true

      // 跳转操作

      if (opts.type === 'navigateTo') {

        Navigator._secretOpen({ url })      // 相当直接执行wx.navigateTo,不会更新逻辑栈

      // 重定向

      } else if (opts.type === 'redirectTo') {

        Navigator._secretReplace({ url })   // 相当直接执行wx.redirectTo,不会更新逻辑栈

      }

    // 返回操作

    } else {

      // 获取逻辑栈

      let routes = Navigator.history

      // 如果10层之外的返回,用navigateTo操作

      // 如果是10层返回到9层,用redirectTo操作

      const operation = (routes.length === Navigator.maxLevel) ? 'redirectTo' : 'navigateTo'

      // 获取要返回的页面路由

      let preRoute

      if (operation === 'navigateTo') {

        // 移除逻辑层中后两个元素:

        // 移除最后一个是因为要返

        // 移除倒数第二个是因为,跳转到倒数第二个页面时会重新插入逻辑栈

        preRoute = routes.splice(routes.length - 2, 2)[0]

      } else {

        // 重定向时只移除最后一个元素

        preRoute = routes[routes.length - 2]

        routes.splice(routes.length - 1, 1)

      }

      // 更新逻辑栈

      Navigator.updateRoutes(routes)

      // 执行自己包装的跳转、重定向方法,该操作会更新逻辑栈

      Navigator[operation](preRoute)

    }

  }

}

</script>

<style lang="scss">

  .main {

    background-color: $white-color;

  }

</style>

原理就是这样,但是有几点需要注意:


业务代码中需要调用自己封装的跳转方法

切记不要直接调用wx的api,也不要使用组件,这样是没法更新js逻辑栈的,正确跳转方式如:Navigator.navigateTo({ url: 'xxx' })。


跳转时要及时更新js逻辑栈(更新时机如上所述),因为这会直接影响中转页的跳转逻辑

这个方案最大的优点在于不用监听页面卸载时对逻辑栈的更新,无需在每个页面里加入更新逻辑栈代码。

相关阅读
网站需要SEO 基本的SEO建站要点
连云港看网
FlashFxp修改FTP密码
深山留言板情人节效果
解析css属性的另类属性之媒体(Media)类型
深山行者留言系统V3.1
asp中eof的介绍
CSS光标属性一览表
共有0条关于《微信小程序页面栈超过【10层】之后无法打开其他页面原因》的评论
发表评论
正在加载评论......
返回顶部发表评论
呢 称:
表 情:
内 容:
评论内容:不能超过 1000 字,需审核,请自觉遵守互联网相关政策法规。
验证码: 验证码 
网友评论声明,请自觉遵守互联网相关政策法规。

您发布的评论即表示同意遵守以下条款:
一、不得利用本站危害国家安全、泄露国家秘密,不得侵犯国家、社会、集体和公民的合法权益;
二、不得发布国家法律、法规明令禁止的内容;互相尊重,对自己在本站的言论和行为负责;
三、本站对您所发布内容拥有处置权。

更多信息>>栏目类别选择
百度小程序开发
微信小程序开发
微信公众号开发
uni-app
asp函数库
ASP
DIV+CSS
HTML
python
更多>>同类信息
uni-app开发表单input组件的一些规则说明自己预留使用
uni-app:使用uni.downloadFile下载word或pdf文件并保存到手机
小程序中利用addPhoneContact将联系人的信息添加到手机通讯录支持保存联系人头像
微信小程序打开客服提示:该小程序提供的服务出现故障,请稍后重试
微信小程序客服会话只能过button让用户主动触发
uni-app开发微信小程序使用button的open-type为contact调用微信客服不能用view或者js调用
更多>>最新添加文章
在Android、iOS、Windows、MacOS中微信小程序的文件存放路径
python通过代码修改pip下载源让下载库飞起
python里面requests.post返回的res.text还有其它的吗
aliyun阿里云续费域名优惠口令(注册、续费都可以使用)
windows7环境下安装配置jdk
python对微信操作要用到这两个库wxpy与itchat
ASP中Utf-8与Gb2312编码转换乱码问题的解决方法页面编码声明
DW设置之后更好用 DreamweaverCS编辑GB2312与UTF-8文件在代码视图中点击鼠标错位问题的解决办法
更多>>随机抽取信息
ASP.NET常用的三十三种实用代码(中)
关于CSS框架的利与弊进行一些对比
一个非常不错的简单的ajax读取新浪rss的小例子
可以生成跟QQ菜单一样的生成器
复选框添加,删除信息,过滤重复
Javascript JS 限制复选框的选择个数