前言
- 常网IT源码上线啦!
- 本篇录入吊打面试官专栏,希望能祝君拿下Offer一臂之力,各位看官感兴趣可移步🚶。
- 有人说面试造火箭,进去拧螺丝;其实个人觉得问的问题是项目中涉及的点 || 热门的技术栈都是很好的面试体验,不要是旁门左道冷门的知识,实际上并不会用到的。
- 接下来想分享一些自己在项目中遇到的技术选型以及问题场景。
当别人给你发红包,如果你不想收~
你这样回:心意和红包,我就挑最贵重的收下啦,红包就不收了,谢谢!
地铁上看到一个文质彬彬的少年~
一、场景还原
请允许我用最简单朴素的话描述。
从A路由--->B路由,此时停留在B路由页面下,点击浏览器自带的返回,期望回到A页面。
结果发现:url是A页面的,但内容还是B页面。
而当前应用是嵌入到其他环境的,被包裹了一层。
二、分析
首先,有请第一位怀疑对象登场。
2.1 beforeEach
初步怀疑是router.beforeEach
的哪个逻辑没有走next(),所以导致他停留下来。
我们写程序的时候,应该要有这种直觉。
于是,我们查看逻辑,发现此时调用H接口成功时,才会去走next()。
那是否是因为网络导致接口响应慢,而影响了next。
2.2 浏览器历史记录
正当我们调试一波,部署线上时,神奇的发现,点击【返回】的时候,连router.beforeEach
都不走,这就有点神奇了。
心想:路由的一切变化,应该都会走beforeEach才对的,尽管的浏览器或者路由跳转。
于是,我咨询了一位朋友。
在使用 Vue Router 中,当使用 history 模式(HTML5 History 模式)时,浏览器返回上一个页面会触发浏览器的历史记录操作,而不会触发 Vue Router 的路由跳转。因为 Vue Router 的 beforeEach 守卫是在路由跳转之前触发的,而浏览器的返回按钮并不是触发路由跳转,而是操作浏览器历史记录。
所以,当用户点击浏览器返回按钮时,页面会直接从浏览器历史记录中获取上一个页面的 URL,并加载对应的页面内容,这个过程是浏览器自身的行为,不会经过 Vue Router,因此也不会触发 beforeEach 守卫以及其他 Vue Router 相关的路由导航守卫。
如果您希望在用户点击浏览器返回按钮时执行一些逻辑,可以使用浏览器原生的 popstate 事件来监听浏览器的历史记录变化。在 popstate 事件中,您可以执行相关的逻辑操作。但是需要注意的是,这种方式不会触发 Vue Router 的路由导航守卫。
完。
我看完是想笑的,虽然心里有一度觉得有点道理,但不管是浏览器操作历史记录,还是会走beforeEach守卫的,她是全局的。
2.3 popstate
提到了一个点,说可以利用popstate事件来执行路由跳转,可以router.go(-1)
,但我认为不好,因为无法确认他会不会走beforeEach
,要是走了,里面next,你popstate也go(-1),就会跳转两次。
Out!
2.4 组件路由守卫
没事,我还有招,竟然全局的路由守卫,我还有其他守卫,我去组件守卫添加一下beforeRouteLeave
让她next。
很遗憾,这里也不会执行。
Out!
2.5 外部js影响?
在html中,我们引入了n个js资源,如:wx的,埋点SDK等等。
是否是因为这些js资源引起,某个代码阻止了其跳转事件。
也有这个可能,但排查起来困难,因为引入资源较多。
2.6 找规律:刷新
如果阁下,阁下会怎么排查?
我将项目的对象都怀疑了一遍,突然想起小时候老师说的,遇到问题不要慌,先找问题所在,那怎么找问题呢?
找规律!
我们的应用,是嵌入到其他应用的,那边点击一个按钮a标签会跳转到我们这边来,其实一开始怀疑是不是那边有什么限制,比如nginx设置了。
但发现,在同等的其他应用没有这个情况,那还是我们自己先找原因。
回归正题,跳到我们应用来,A路由--->B路由。
突然发现:如果我们此时在任意的路由手动F5刷新一下,即可正常回退上一步。
有了这个规律,我突然想起,之前有一个需求:
url?token=base64,由于token很长,而且会显示在页面上,希望我们拿到token存到vuex中,用js程序把url上的token给清除掉。
vbnet
delete to.query.token;
router.push({ name: to.name, query: {...to.query } });
即:
url?token=1
url
我想,或许和这里有关,导致路由、历史记录错乱,才会回退不回去。
然后我们手动刷新一下,记录就正常了,也就能正常回退。
三、解决方法
有两个解决方法。
3.1 去掉自动删除token
这一步去掉。
vbnet
delete to.query.token;
router.push({ name: to.name, query: {...to.query } });
直接走next。
当然,原本的需求,我们最好不要去做更改,只能程序自己想办法了。
3.2 自动刷新
既然刷新能解决问题,那我们就让他进入我们的应用的时候,刷新一下,在源头处理就好。
源头解决好了,后面的路由跳转就没问题了。
我们只页面加载第一次的时候,做手动刷新。
javascript
mounted(){
if(this.$store.getters.get_isFirstRefresh){
this.$store.dispatch('set_isFirstRefresh',false);
this.$router.go(0) // 刷新
}
}
vuex
javascript
const homeInfos = {
state: {
isFirstRefresh: true
},
mutations: {
set_isFirstRefresh(state, isFirstRefresh) {
state.isFirstRefresh = isFirstRefresh
}
},
actions: {
set_isFirstRefresh(state,isFirstRefresh) {
state.commit('set_isFirstRefresh', isFirstRefresh)
}
},
getters: {
get_isFirstRefresh: (state) => {
return state.isFirstRefresh
}
}
}
export default homeInfos
至此撒花~
后记
我们在实际项目中或多或少遇到一些奇奇怪怪的问题。
在此期间,不要慌是首选,多凭借自己的经验找感觉,或许是有一个需求改了一两行不起眼的代码导致。
大动脉没切中,即安心。
如果有其他更好的方法也欢迎评论区见,这里提供的只是诸多方法之一。
最后,祝君能拿下满意的offer。
我是Dignity_呱,来交个朋友呀,有朋自远方来,不亦乐乎呀!深夜末班车
👍 如果对您有帮助,您的点赞是我前进的润滑剂。