美文网首页vue那些年使用vue的各种问题
Vue-router如何实现拦截物理返回键的回退功能

Vue-router如何实现拦截物理返回键的回退功能

作者: microkof | 来源:发表于2019-10-23 15:35 被阅读0次

    前言

    拦截物理返回键的需求其实还是蛮多的,比如,点击返回键关闭弹层,点击返回键避免没有保存就退出,等等。

    如何拦截物理返回键这个事,网上有很多搜索结果,但是真正解决问题的文章我硬是没有找到,瞎鸡巴写的倒是很多,所以干脆自行研究了一下,给大家介绍一个方法。

    定个需求

    现在我的项目中有一个购买商品的弹层,也就是sku,那么,当点击物理回退键时,如果弹层显示着,我就让它隐藏,而且要阻止退回到上一页。

    浏览器困境

    拦截物理键,原则上是监听popstate事件,然而,现实很残酷,因为popstate事件的意思是路由已经变化完成,也就是说,并没有一种方法真正监听物理键的点击。一旦触发popstate,其实就已经晚了,因为路由已经变化了,你已经无法拦截。

    因此,window.addEventListener("popstate", fn)的回调函数fn,是在浏览器回退之后执行,这个回退是浏览器自己执行的,不受任何控制,无论是加上event.preventDefault()还是return false都白扯。这就好比,一个元素已经监听到了click,你无论加什么代码,都不能让浏览器当做没有点击(CSS层面的阻止点击另说)。

    怎么办?

    只能是给浏览器跪下,先听从它回退,然后再重新push回来。好在,Vue-router给我们提供了push回来的方法。

    好了,我们开始。

    方法

    在需要关闭sku弹层的组件(必须是路由级组件)里加入:

      beforeRouteLeave(to, from, next) { // 仅适用于本页面不作为H5着陆页的情况
        if (this.skuShow) {
          this.$store.commit('SET_SKU_SHOW', false)
          next(false)
        } else {
          next()
        }
      },
    

    核心代码是next(false)。根据官方说法:

    如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。

    所以其实也是push回来的道理。

    着陆页困境

    最后还有一个重要的问题就是,如果你是在项目着陆页(也就是浏览器打开的项目的第一个页)弹了一个sku层,那么这个方案就无效了,道理也很简单,浏览器先回退,有3种可能:

    1. 可以回退,但退出项目了,退到先前打开的其他网站的页面了,这时候再想push回来也白扯了,因为项目都退了,怎么执行push?
    2. 无法回退,既然无法回退,那么就不触发beforeRouteLeave钩子,所以也不能执行代码。
    3. 如果项目是在APP的webview中打开的,一般来讲是不存在第一种情况的,只可能是第二种情况,那么当无法回退的时候,APP会退出webview,也依然不会触发beforeRouteLeave钩子。

    所以结论就是:

    1. web端,想要物理回退键只关闭sku,就要另想办法了,而且几乎没办法,至少我是没办法。
    2. 如果是在APP的webview中,办法还是有的,就是APP监听物理返回键,监听到之后,调用js环境的window对象上的一个方法,这个方法的作用是读取vuex中的skuShow的值,如果是true,则APP拦截物理键,方法也把skuShow改为false,如果skuShow本身就是false,则正常操作即可。

    当然了,首页就出现弹出层这种交互方式,本身也应该避免,因为首页往往是作为导航用的,应该减弱交互。尤其是单纯H5页面,首页一定不要弄弹出层,因为用户随便就退出网站了,最后损失的是你的访问量。

    相关文章

      网友评论

        本文标题:Vue-router如何实现拦截物理返回键的回退功能

        本文链接:https://www.haomeiwen.com/subject/pfjkvctx.html