TOC
先来阐述一下需求
首先我拥有一个详情页面 B 用户可以进入到页面 B 之中分享出去页面 B 但别的用户通过地址直接进入页面 B 这时候 如果用户按了一下返回按钮 需要返回主页
很明显这个需求其实是有点违背 Web 的一些准则的。用户对应他的路由堆栈应该是有一定的掌控和知情的,这个有点破坏的嫌疑,但是没办法,有这个需求。
解决方案
我的大致思路是利用检测popstate这个事件来进行手动路由挑战,但是由于用户刚进入页面,是没有路由栈的,也就是意味着不能监听这个事件,那么我们就手动给用户加个堆栈项,要注意的是加的堆栈项地址要和现在的页面相等,不然就会发现页面跳转了。
微信的弱智坑
情况1 用户第一次打开页面B > 进入生命周期 > 加个路由堆栈项 > 开始监听Popstate 情况2 用户后续打开页面B > 进入生命周期 > 加个路由堆栈项 > 页面刷新??? > 在进入周期 > 开始监听popstate
发现区别了没有,当用户第二次或者后续打开这个页面,会导致页面刷新。
所以我设置了history的length需求等于2,让页面第二次进入到时候再加个路由堆栈项,否则是无法成功监听到的。
其实具体原理我也没搞明白,为什么第二次进入,不加堆栈项监听就无效,不过我也不愿意进一步了,主要这需求我就觉得不太正常,微信也有坑,鬼知道微信到底干了什么事。有效能用就是了。我个人觉得还是微信的臭锅。
export default {
beforeRouteEnter(to, form, next) {
// 这里的判断必须为2 不能为1
if (window.history.length <= 2 && form.matched.length <= 0) {
next(vm => {
pushHistory()
function pushHistory() {
var state = {
title: 'title',
url: '#' + window.location.href.split('#')[1]
}
window.history.pushState(
state,
'title',
'#' + window.location.href.split('#')[1]
)
}
localStorage.setItem('needBack', '1')
vm.listenBack()
})
} else {
next(vm => {
vm.listenBack()
})
}
},
methods: {
listenBack() {
this.timer = setTimeout(() => {
let needBack = localStorage.getItem('needBack')
if (needBack) {
localStorage.removeItem('needBack')
const back = () => {
this.$router.push({ name: 'nHome' })
window.removeEventListener('popstate', back, false)
}
window.addEventListener('popstate', back, false)
}
return
}, 500)
}
}
}
缺点
当用户返回 指定页面后 再按一次会返回页面B 因为这个堆栈项其实依旧存活在堆栈之中,并没有被消耗掉。这是不完美的一点。本身history API 也是不支持删除路由堆栈的。