萌萌新的成长 2023-05-27 11:34 采纳率: 33.3%
浏览 41

uniapp公众号h5物理按钮返回问题

需求:页面a、b、c,并且a=>b=>c,b和c都有自定义返回按钮,c页面需要在页面返回(物理返回按钮或者自定义返回按钮)前给提示,并且每一个页面只能返回到它的入口页

img

解决方案:在onLoad里面pushState, onShow监听popstate
问题:
1、a navigateTob,b navigateToc,在c自定义返回按钮点击的回调函数是popstate的回调函数,点击自定义按钮并且确认离开uni.navigateBack,页面闪一下它会返回当前页面,我理解是pushstate添加了一个历史记录就有了两个记录,back的时候回第一个记录了,于是我uni.navigateBack({ delta:2 }),这时候它可以回到b页面了,但是物理返回按钮返回却直接跳到a页面了,同一个回调函数为什么会有这样的情况?
2、a navigateTob,b redirectToc,返回方法改为uni.redirectTo,c=>b=>a全程使用物理返回按钮返回功能正常,
①当我在c使用自定义返回按钮返回,会去到b
b物理返回按钮返回时,b会去到c
c这时候如果用物理返回按钮会回到b
④再物理返回按钮会回到a
我的理解:①之前的历史记录是[a,c,c],①之后变成[a,c,b],
②之后变成[a,c],③之后变成[a,b],④之后变成[a],
而如果在③用自定义按钮返回,③④会无限循环
为什么全程物理返回按钮没问题,加入了自定义返回按钮的操作就变的不一样了?
3、在2的问题上,我在b也监听popstate,强行让页面跳到a,这时候a物理返回在一些情况会去到b,一些情况去到c,就更复杂了,不描述。
4、在3的问题上,我在a也监听popstate,这时候其它不监听popstate的页面回到a的时候,a会被重新加载等于location.href,这时候首页store缓存的数据就每没有缓存的作用了,把其它没监听的页面都加上popstate监听就不会出现这个问题。

onHide() {
    // 卸载监听
    window.removeEventListener('popstate', this.goBack);
},
beforeDestroy() {
    // 卸载监听    
    window.removeEventListener('popstate', this.goBack);
},
onUnload(){
    // 卸载监听
    window.removeEventListener('popstate', this.goBack);
},
async onLoad(option) {
            this.$historyUrl();
}
async onShow() {
            window.addEventListener('popstate', this.goBack); 
}
async  goBack() {
    this.modalType = 2;
    this.showBox = true;
    const res = await new Promise(resolve => {
       uni.$on('leave', (res) => { // 监听是否离开弹窗点击按钮
        resolve(res)
       });
    })
    if (!res) {
        this.$historyUrl();
    } else{
        uni.redirectTo({
            url: redirectMap[this.subType]
        })
    }
    this.showBox = false;
},

有没有其它方案解决这个需求?

  • 写回答

1条回答 默认 最新

  • 关注

    🤔可以考虑通过 uni.navigateBack()、uni.redirectTo() 等 uni-app 提供的 API 来实现需求。具体实现方案如下:
     
    1、在每个页面的 onLoad() 钩子中使用 uni.addInterceptor() 方法注册一个拦截器,用于拦截页面的返回操作:

    
    export default {
      onLoad() {
        // 注册拦截器
        uni.addInterceptor((to, options) => {
          // 保存当前页面的路径
          this.fromUrl = getCurrentPages().slice(-2)[0].route
    
          // 如果是返回操作,则弹出确认框
          if (options.navigateBack && options.delta === 1) {
            // 执行弹框操作,返回 true 或 false
            const shouldBack = await this.showModal()
    
            // 根据弹框操作的结果进行返回或取消
            if (shouldBack) {
              // 执行返回操作
              uni.navigateBack({ delta: 1 })
            } else {
              // 取消返回操作,阻止拦截器继续执行
              return Promise.reject('cancel')
            }
          }
    
          // 放行拦截器
          return options
        })
      },
      methods: {
        async showModal() {
          return new Promise(resolve => {
            uni.showModal({
              title: '确定返回吗?',
              success(res) {
                resolve(res.confirm)
              },
              fail() {
                resolve(false)
              }
            })
          })
        }
      }
    }
    

    在拦截器中,如果发现当前操作是返回操作,则弹出确认框,根据确认框的结果决定是否执行返回操作。
     
    2、在每个页面的 onUnload() 钩子中使用 uni.removeInterceptor() 方法注销拦截器:

    
    export default {
      onUnload() {
        // 注销拦截器
        uni.removeInterceptor()
      }
    }
    

    在页面卸载时,确保注销掉之前注册的拦截器,避免出现意外的行为。
     
    3、在需要自定义返回行为的页面中,使用 uni.navigateBack() 或 uni.redirectTo() 方法来实现自定义返回行为:

    
    export default {
      methods: {
        goBack() {
          // 执行自定义返回行为
          uni.redirectTo({
            url: '/pages/b/index'
          })
        }
      }
    }
    

    在执行自定义返回行为时,可以使用 uni.navigateBack() 或 uni.redirectTo() 等 uni-app 提供的 API 来实现,在拦截器中不再拦截这些自定义的返回操作。
     
    4、为了确保用户只能返回到当前页面的入口页面,可以在 onLoad() 钩子中记录当前页面的入口页面,然后在拦截器中进行判断:

    
    export default {
      onLoad() {
        // 记录当前页面的入口页面
        const pages = getCurrentPages()
        this.fromUrl = pages[pages.length - 2]?.route || ''
    
        // 注册拦截器...
      },
      methods: {
        showModal() {
          // ...
        }
      }
    }
    

    在进行返回操作时,可以比较当前页面和入口页面的路径是否相同,如果不同则不允许返回。

    评论 编辑记录

报告相同问题?

问题事件

  • 修改了问题 5月27日
  • 修改了问题 5月27日
  • 创建了问题 5月27日

悬赏问题

  • ¥15 is not in the mmseg::model registry。报错,模型注册表找不到自定义模块。
  • ¥15 安装quartus II18.1时弹出此error,怎么解决?
  • ¥15 keil官网下载psn序列号在哪
  • ¥15 想用adb命令做一个通话软件,播放录音
  • ¥30 Pytorch深度学习服务器跑不通问题解决?
  • ¥15 部分客户订单定位有误的问题
  • ¥15 如何在maya程序中利用python编写领子和褶裥的模型的方法
  • ¥15 Bug traq 数据包 大概什么价
  • ¥15 在anaconda上pytorch和paddle paddle下载报错
  • ¥25 自动填写QQ腾讯文档收集表