检测 Vue-Router 导航守卫中的后退按钮

Posted

技术标签:

【中文标题】检测 Vue-Router 导航守卫中的后退按钮【英文标题】:Detect Back Button in Navigation Guards of 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 本身没有,但任何解决方法也可以在这里工作。还是有其他更喜欢的方式来识别它?

【问题讨论】:

请阅读:github.com/vuejs/vue-router/issues/2796#issuecomment-498348465 【参考方案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));
    

    用您自己的“导航”函数包装“router.push” 在调用 router.push 之前,将“internalNavigation”标志设置为 true 使用 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);
      
   

最好的问候!

【讨论】:

以上是关于检测 Vue-Router 导航守卫中的后退按钮的主要内容,如果未能解决你的问题,请参考以下文章

vue-router导航守卫(router.beforeEach())的使用

vue-router 实现导航守卫(路由卫士)

vue-router有哪几种导航钩子( 导航守卫 )?

vue-router 导航守卫

vue-router导航守卫的简单使用

vue-router --- 路由守卫类型