检测 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 导航守卫中的后退按钮的主要内容,如果未能解决你的问题,请参考以下文章