【问题标题】:Detect Back Button in Navigation Guards of Vue-Router检测 Vue-Router 导航守卫中的后退按钮
【发布时间】:2019-01-29 12:11:57
【问题描述】:

路线如何改变,对我来说很重要。 所以,我想在浏览器或 gsm 的后退按钮更改路线时捕捉到。

这就是我所拥有的:

router.beforeEach((to, from, next) => {
  if ( /* IsItABackButton && */ from.meta.someLogica) {
    next(false) 
    return ''
  }
  next()
})

我可以使用一些内置的解决方案来代替IsItABackButton 评论吗?我猜 Vue-router 本身没有,但任何解决方法也可以在这里工作。还是有其他更喜欢的方式来识别它?

【问题讨论】:

标签: javascript cordova vue.js vuejs2 vue-router


【解决方案1】:

这是我找到的唯一方法:

我们可以监听 popstate,把它保存在一个变量中,然后检查那个变量

// This listener will execute before router.beforeEach only if registered
// before vue-router is registered with Vue.use(VueRouter)

window.popStateDetected = false
window.addEventListener('popstate', () => {
  window.popStateDetected = true
})


router.beforeEach((to, from, next) => {
  const IsItABackButton = window.popStateDetected
  window.popStateDetected = false
  if (IsItABackButton && from.meta.someLogica) {
    next(false) 
    return ''
  }
  next()
})

【讨论】:

  • 我期待 Navigation-Guards 为这个问题提供更好的解决方案,但可能这确实是目前我们唯一能解决这个问题的办法。
  • @Nuno Balbona Pérez,看起来 popstate 事件处理程序运行 AFTER router.beforeEach 回调。我认为这不会按原样工作。
  • 点赞!你把这段代码放在哪里?在 router.js 里面?我在这里使用 nuxt
  • 处理调用顺序问题 有可能超时或 nextick-wrap beforeEach 逻辑。不优雅,但这个解决方案效果很好。更大的问题是,这个解决方案也会对 forward-btn 点击做出反应——但公平地说,这个问题并没有说什么哈哈
【解决方案2】:

正如@Yuci 所说,所有路由器钩子回调都是在之前更新popstate(因此对这个用例没有帮助)

你可以做什么:

methods: {
    navigate(location) {
        this.internalNavigation = true;
        this.$router.push(location, function () {
            this.internalNavigation = false;
        }.bind(this));
    }
}
  1. 用您自己的“导航”函数包装“router.push”
  2. 在调用 router.push 之前,将“internalNavigation”标志设置为 true
  3. 使用 vue router 'oncomplete' 回调将 internalNavigation 标志设置回 false

现在您可以在 beforeEach 回调中检查标志并进行相应处理。

router.beforeEach((to, from, next) => {
  if ( this.internalNavigation ) {
      //Do your stufff
  }
  next()
})

【讨论】:

    【解决方案3】:

    这很容易做到。

    const router = new VueRouter({
      routes: [...],
      scrollBehavior (to, from, savedPosition) {
        if (savedPosition) {
          // History back position, if user click Back button
          return savedPosition
        } else {
          // Scroll to top of page if the user didn't press the back button
          return { x: 0, y: 0 }
        }
      }
    })
    

    检查这里: https://router.vuejs.org/guide/advanced/scroll-behavior.html#async-scrolling

    【讨论】:

    • 您能解释一下这是如何检测检测到后退按钮的吗?如何使用它来解决 OP 的书面问题?与beforeEach 相关的scrollBehavior 事件如何触发?
    • 如果您需要让应用程序的其余部分知道它是后退/前进的,您也可以添加to.meta.fromHistory = (savedPosition !== null);
    【解决方案4】:

    对@yair-levy 的回答略有改进。

    push 包装到自己的navigate 方法并不方便,因为您通常想从不同的地方调用push()。相反,可以在一个地方修补路由器原始方法,而无需更改剩余代码。

    以下代码是我的 Nuxt 插件,用于防止后退/前进按钮触发导航(在 Electron 应用中用于避免鼠标附加“后退”按钮导致后退,这会在 Electron 应用中造成混乱) 相同的原理可用于 vanilla Vue,并与您的自定义处理一起跟踪常见的后退按钮。

    export default ({ app }, inject) => {
      // this is Nuxt stuff, in vanilla Vue use just your router intances 
      const { router } = app
    
      let programmatic = false
      ;(['push', 'replace', 'go', 'back', 'forward']).forEach(methodName => {
        const method = router[methodName]
        router[methodName] = (...args) => {
          programmatic = true
          method.apply(router, args)
        }
      })
    
      router.beforeEach((to, from, next) => {
        // name is null for initial load or page reload
        if (from.name === null || programmatic) {
          // triggered bu router.push/go/... call
          // route as usual
          next()
        } else {
          // triggered by user back/forward 
          // do not route
          next(false)
        }
        programmatic = false // clear flag
      })
    }
    

    【讨论】:

      【解决方案5】:

      在我的 Vue 应用程序中检测后退按钮导航与其他类型的导航相比,我遇到了同样的问题。

      我最终做的是向我真正的内部应用导航添加一个哈希,以区分预期的应用导航和后退按钮导航。

      例如,在这条路线/page1 上,我想捕捉返回按钮导航以关闭打开的模型。想象一下,我真的想导航到另一条路线,我会在该路线上添加一个哈希:/page2#force

      beforeRouteLeave(to, from, next) {
          // if no hash then handle back button
          if (!to.hash) {
            handleBackButton();
            next(false); // this stops the navigation
            return;
          }
          next(); // otherwise navigate
      }
      

      这是相当简单的,但它有效。如果您在应用程序中使用哈希值超过此值,您将需要检查哈希实际包含的内容。

      【讨论】:

        【解决方案6】:

        performance.navigation 已被弃用,所以请注意! https://developer.mozilla.org/en-US/docs/Web/API/Performance/navigation

        当您想要注册任何全局事件侦听器时,您应该非常小心。自注册时刻起每次都会调用它,直到您手动取消注册。对我来说,情况是我在创建组件时注册了 popstate 侦听器以侦听并在以下情况下调用某些操作:

        • 浏览器返回按钮
        • alt + 箭头返回
        • 鼠标中的后退按钮

        被点击。之后我取消注册 popstate 侦听器,不要在我不想调用它的其他组件中调用它,保持你的代码和方法调用干净:)。

        我的代码示例:

            created() {
              window.addEventListener('popstate', this.popstateEventAction );
            },
            methods: {
              popstateEventAction() {
                // ... some action triggered when the back button is clicked
                this.removePopstateEventAction();
              },
              removePopstateEventAction() {
                window.removeEventListener('popstate', this.popstateEventAction);
              }
           }
        

        最好的问候!

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-02-10
          • 2019-10-21
          • 1970-01-01
          • 2021-06-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多