评论

各种路由情况下使用 getCurrentPages 可能存在的陷阱

介绍getCurrentPages在 navigateTo/navigateBack 等各种路由情况下可能存在陷阱

废话不多说,直接上微信API。

PageObject[] getCurrentPages()

获取当前页面栈。数组中第一个元素为首页,最后一个元素为当前页面。

注意:

  • 不要尝试修改页面栈,会导致路由以及页面状态错误。

  • 不要在 App.onLaunch 的时候调用 getCurrentPages,此时 page 还没有生成。

 这是微信官方对 getCurrentPages 做的解析和使用注意点,相信大家都很熟悉了。文档中明确指出

 不要在 App.onLaunch 的时候调用 getCurrentPages,此时 page 还没有生成。

那么是不是只要我们不再 App.onLaunch 中使用,getCurrentPages 就会按照我们的预期来工作呢?其实并不尽然。

我在这里为了演示,写了两个页面 First Page 和 Second Page。First Page 可以跳转到 Second Page , Second Page 也可以回退到 First Page.

并且在两个页面的 onShow 方法中调用了 getCurrentPages 方法。

  1. onShow(){

  2.     let pages = getCurrentPages();

  3.     console.log('------------------- First Page onShow方法中获取栈内页面');

  4.     console.log(pages);

  5. },

重新运行小程序,从 First Page 跳转到 Second Page ,观察控制台日志

可以看到在 First Page 的 onShow 方法中打印的包含一个对象H的数组, 在 Second Page 的 onShow 方法中打印出了包含两个对象H的数组,H 可以理解为Page实例对象的名称。这和我们预期的是一样的。

接下来我们举个特别点的栗子,怎么特别呢?这回我们的栗子没用糖炒,炒栗子的伙计把“路由”错当成糖了。那我们就来看看当栗子,啊...,不,应该是 getCurrentPages 遇到“路由”后会变成什么味儿呢? 

首先我们来看看微信小程序API中都有哪些路由

没错就是这几个控制小程序页面跳转的全局函数。我们在这里尝试一下最常用的两个 navigateTo 和 navigateBack,其他的同理。

下面我们来看看 First Page 的跳转方法代码:

  1. /**

  2. * 跳转到 Second Page

  3. */

  4. navigateToSecondPage() {


  5. wx.navigateTo({

  6. url: '/other/other',

  7. })


  8. let pages = getCurrentPages();


  9. console.log('------------------- First Page navigateToSecondPage方法中获取栈内页面');

  10. console.log(pages);

  11. },

我们重新运行一下小程序后点击 First Page 中 跳转到Second Page的按钮,观察一下控制台的日志输出情况

哎哎哎......?怎么哪里好像不对呢?炒栗子的伙计说在点击按钮的时候我明明往锅里加了一个 Page 实例啊,为什么我放进去后没有马上看见呢?完了这下炒出来的栗子又变味了。

我们知道 navigateTo 方法肯定是向页面栈里又加入了一个新页面实例的,那么我们去 Second Page 中的 onLoad 方法中看看,有几个 Page 实例:

哎呦,在Second Page 中明明就是两个,怎么在跳转执行后没有看到呢?伙计想是不是自己太心急了,于是他在加入第二个Page后并没有马上去看而是出去抽了根烟。

  1. /**

  2. * 跳转到 Second Page

  3. */

  4. navigateToSecondPage() {


  5. wx.navigateTo({

  6. url: '/other/other',

  7. })


  8. let timerId = setTimeout(function(){


  9. let pages = getCurrentPages();

  10. console.log('------------------- First Page navigateToSecondPage 1S later 方法中获取栈内页面');

  11. console.log(pages);

  12. }, 1000);

  13. },

抽完烟后回来发现又正常了

点击完跳转按钮1S后,第二个Page实例奇迹般地出现了。伙计有点兴奋啊。于是决定了以后碰到 getCurrentPages 和 路由就出去抽根烟,啊...... ,不不不,是等会再看。可是这并不是万全之策。我们都知道 setTimeOut 的运行机制,它是在当前任务栈内的任务执行完毕后再执行 setTimeOut 里任务。这个任务的执行开始时间是当前任务栈内所有的任务执行完成的耗时 + setTimeOut 的延迟时间,也就是说是一个不确定的时间,换个说法就是伙计出去抽根烟回来不一定能看见第二个Page实例。总感觉不是那么安全,那怎么办呢?

我们仔细阅读 navigateTo 的使用文档就会发现,它除了可以指定跳转路径(url)外,还可以添加三个回调方法。


那么现在我们根据使用文档来试着修改一下我们查看 page 实例的时间。我们等到跳转成功后就立马去查看。

  1. /**

  2. * 跳转到 Second Page

  3. */

  4. navigateToSecondPage() {


  5. wx.navigateTo({

  6. url: '/other/other',

  7. success: function(){

  8. let pages = getCurrentPages();

  9. console.log('------------------- First Page navigateTo Success 方法中获取栈内页面');

  10. console.log(pages);

  11. }

  12. })

  13. },

重新运行一下程序:

好像这个success回调也不是很靠谱,还是得等一小会儿才能看见第二个Page实例。

这是 navigateTo ,下面我们来看看 navigateBack 。

  1. navigateBack(){


  2. let pages = getCurrentPages();


  3. console.log('------------------- Second Page navigateBack 执行之前获取栈内页面');

  4. console.log(pages);


  5. if(pages.length > 1){


  6. wx.navigateBack({

  7. delta: 1,

  8. success: function(){

  9. console.log('-------------------Second Page navigateBack Success获取栈内页面');

  10. let pages1 = getCurrentPages();

  11. console.log(pages1);

  12. }

  13. });

  14. }

  15. },

我们清空控制台日志,然后点击 Second Page 的 返回 First Page 按钮

我们可以看到 wx.navigateBack 的 success 函数中可以拿到准备的页面堆栈数据。当然你也可以出去抽根烟等会回来再看数据。

所以我们根据上面的Demo可以得出两个小结论:

1 wx.navigateTo 执行之后只能通过延时的方法去获取准确的页面堆栈数据,具体延时多少看你炒栗子的经验喽。

2 wx.navigateBack 执行后可以通过延时和回调方法进行获取页面堆栈数据。



至于其他的路由的情况就不啰嗦那么多了,结论如下:

3 wx.switchTab 执行后可以通过延时和回调方法进行获取页面堆栈数据, 同 wx.navigateBack。

4 wx.reLaunch 执行之后只能通过延时的方法去获取准确的页面堆栈数据, 同 wx.navigateTo。

5 wx.redirectTo 没有办法在执行wx.redirectTo的页面内获取准确的页面堆栈数据。

怎么样,有没有感觉很  因吹丝汀 啊.....

好了,大概就这些了。

重要的事情说三遍:

尽量不要在执行完路由函数后立即调用 getCurrentPages 函数!

尽量不要在执行完路由函数后立即调用 getCurrentPages 函数!

尽量不要在执行完路由函数后立即调用 getCurrentPages 函数!

不然你会吃到怪味的栗子,希望可以帮到大家,如果哪些地方写的不对或不够准确,请大家批评指正。


点赞 1
收藏
评论

3 个评论

  • 陈三百
    陈三百
    2020-06-30

    了解一下异步这个概念哦, 页面跳转是异步的

    2020-06-30
    赞同
    回复 1
    • 陈三百
      陈三百
      2020-06-30
      如果有需要同步处理的话,promise化就行了
      2020-06-30
      回复
  • Jeff
    Jeff
    2020-02-06

    正好我也研究到这个,这个抽根烟的时间很不可靠啊,我想干脆持续setTimeout直到堆栈中有新的页面

    2020-02-06
    赞同
    回复 1
    • momo
      momo
      2020-02-12
      你说的很对,抽根烟的时间就是想说明时间的不可靠性,如果给 setTimeout 一个足够长的时间,是可以等到新页面进入到页面栈内,可是会造成时间的浪费,也可能会有其他很多新页面进入到栈内,增加后续操作的复杂性。
      2020-02-12
      回复
  • momo
    momo
    2019-12-12

    写的糙了点,先记录一下,后期重新整理一下

    2019-12-12
    赞同
    回复
登录 后发表内容