程序员玛丽的星海方舟

各种问题的发现、解决与感想

前段时间参与了一个项目的开发,共计超过一个月的时间。工作量其实是非常饱和的,并且在接手各种老旧工程的时候经历了很多奇奇怪怪的问题,有的至今难以解决。特此分享一下在这段项目中发现的一些问题解决方案及感想。

目录:


重定向到统一登录页面后,返回的地址默认是网站首页的解决方案

问题描述:网站未登录时重定向到统一登录页面,登录成功自动返回时返回的是网站首页,丢失了后面的路由部分,不能按照预期返回原来的页面。

解决方式:未登录重定向前,将原先的url(删去携带的用户令牌信息)完整保存在Session Storage(浏览器临时存储)中。在进入网站首页时,检测Session Storage是否保存了url,如果有的话,重定向到该url,并删除存储即可。

代码示例:

1
2
3
4
// 重定向前
const unsavedHref = window.top.location.href // 获取窗口url
// 我这边加入了删除用户令牌信息的代码(使用正则)
window.top.sessionStorage.setItem('unsavedHref', unsavedHref) // 将url保存在sessionStorage里
1
2
3
4
5
6
7
// 登录成功回到网站首页后
const unsavedHref = window.sessionStorage.getItem('unsavedHref') // 获取sessionStorage,如果没有则会得到undefined
if (unsavedHref) {
// 如果sessionStorage中存在未保存链接,则恢复
window.sessionStorage.removeItem('unsavedHref') // 删除存储,这是为了防止后续正常访问首页时也被重定向到存储中的链接
window.top.location.href = unsavedHref // 进行跳转
}

跨域传输数据的解决方案

问题描述:A页面中存在一定的数据,需要在跨域打开的B页面中获取使用。

方案一:使用url传参的方式。

实现方式:A页面跳转到B页面时,在url中拼接?data=<…>形式的参数。B页面启动时,获取到url中的参数即可。

优点:速度快,B页面启动后立刻能获取到。

缺点:数据过长的时候,url长度可能会被浏览器限制。

方案二:使用window.postMessage方法。

技术前提:使用window.open打开页面时,A页面可获取到B页面的窗口对象,B页面也可通过window.opener获取到A页面的窗口对象。

具体过程:B页面加载完成并绑定监听器后,先发送消息告知A页面;A页面接收到消息后,向B页面发送消息传递数据;B页面接收到消息后,则根据消息中的数据执行操作。

优点:无需考虑数据的长度限制。

缺点:异步操作,需要一定时间才能完成;A、B页面都需要明确对方的源地址;需要A页面保持开启才会发送数据。

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// A页面 - 打开B页面前
const nextOrigin = 'https://marycly.github.io' // B页面的源地址
const nextUrl = 'https://marycly.github.io/archives/' // B页面的完整打开地址
const parseValue = 'hello' // 要传递的数据

window.addEventListener('message', e => {
if (!e.origin.includes(nextOrigin)) {
return // 任何消息监听器里都应该加上这个判断,不仅可以区分不同地址发来的消息所产生的不同效果,也可以防止未知网站的消息攻击
}
if (this.receiveMessageTimeout) {
window.clearTimeout(this.receiveMessageTimeout)
}
this.receiveMessageTimeout = window.setTimeout(() => {
this.nextPage.postMessage(parseValue, nextOrigin) // 这是最终会干的事情,向B页面发送数据
}, 500)
// 这里小小做了一个0.5s延时的消抖,防止消息重复发送
})
this.nextPage = window.open(nextUrl) // 然后打开B页面,并保存窗口对象到变量中,便于监听器调用
1
2
3
4
5
6
7
8
9
10
11
12
13
// B页面 - 加载完成后
const lastOrigin = 'https://anyone.hello' // A页面的源地址

window.addEventListener('message', e => {
if (!e.origin.includes(lastOrigin)) {
return // 任何消息监听器里都应该加上这个判断,不仅可以区分不同地址发来的消息所产生的不同效果,也可以防止未知网站的消息攻击
}
// 使用e.data干任何事!
console.log(e.data)
this.lastPageData = e.data
})
const lastPage = window.opener // 通过opener获取A页面的窗口对象
lastPage.postMessage('I am all okay!', lastOrigin) // 向A页面表示你已经准备好接收数据了

无法更改源码时阻止网页中默认弹出提示的解决方案

问题描述:工程所使用的一个依赖包中有这样一个逻辑,提交数据成功时会默认弹出一个提示(element-ui的message组件)。现需要阻止该提示,但依赖包的内容难以直接更改。

解决方式:获取该message组件弹窗显示的元素类名,在弹窗出现时使用querySelector找到该元素,并移除它。

1
document.querySelector('.el-message').remove()

对付前人写的坏代码的心得感想

当接手某个工程的时候,有时会发现一些不规范的,逻辑错误的,或是造成了全局性不良污染的代码。我认为比较合适的处理方式如下:

  1. 首先,需要仔细评估该段代码的影响范围。如果牵涉的范围非常大,且依赖于该代码的功能都能够正常运行,则不应轻易更改,而考虑使用局部重写的方式解决问题。

  2. 然后,需要理解该段代码的意义和作用,确定自己的更改是否100%不影响原先的功能。如果不确定,尝试跟原开发者联系确认。

  3. 如果影响范围较小且能确保不影响逻辑,或者影响范围只有正在开发的当前页面或模块,便可以进行修改。修改后必须要经过反复的自测验证,保证功能正常运作。

  4. 有时某段有问题的代码会随着工程体量的增加而积重难返,这时大概率是要对它妥协,将就总比意外好。


总结

再也不想加班和直面屎山了!