VUE中使用localStorage实现跨标签页面的通信
前言目前出现了一个需求,需要父页面打开新的子页面,子页面提交表单之后,关闭子页面,然后把数据返回给父页面。本来考虑使用sharedWorker,但是由于兼容性太差了,就弃用了。看到网上的介绍可以使用localStorage来实现,我就尝试了下。下面是一些具体的细节。开始整体流程如图所示:需求分析子页面需要知道自己的父页面对应的是谁,所以父页面打开子页面的时候需要传输一个父页面的KEY值由于表单是使
前言
目前出现了一个需求,需要父页面打开新的子页面,子页面提交表单之后,关闭子页面,然后把数据返回给父页面。
本来考虑使用sharedWorker
,但是由于兼容性太差了,就弃用了。看到网上的介绍可以使用localStorage
来实现,我就尝试了下。下面是一些具体的细节。
开始
整体流程如图所示:
需求分析
- 子页面需要知道自己的父页面对应的是谁,所以父页面打开子页面的时候需要传输一个父页面的
KEY
值 - 由于表单是使用
dialog
来显示,需要注意避免出现事件重复注册的,及时销毁事件,保留监听事件的唯一。 - 由于保存的时候只会出现单一数据变化,所以只需要维护同一个
localStorage
对象即可。 - 父页面接受数据的时候,也需要校验子页面传输的数据是否属于自己。
- 最终的数据是否关联成功,由父页面的保存决定,子页面的数据是无状态的。
实现原理
localStorage
中支持监听storage
变化时的事件,并且只有在不同标签页面,同源网页的时候才会触发,这里恰好解决的我们的需求:
window.addEventListener('storage', callback);
代码实现
由于localStorage
的API比较简单, 所以这里就不在这里介绍。
为了后续的拓展和方便调用,我这里就将localStorage
一些操作做了简单的封装。
function generateUUID() {
let d = new Date().getTime();
if (window.performance && typeof window.performance.now === 'function') {
d += performance.now(); // use high-precision timer if available
}
const uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
// eslint-disable-next-line no-bitwise
const r = (d + Math.random() * 16) % 16 | 0;
d = Math.floor(d / 16);
// eslint-disable-next-line no-bitwise
return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16);
});
return uuid;
}
export function initStorage(callback) {
window.addEventListener('storage', callback);
}
export function removeStorage(callback) {
window.removeEventListener('storage', callback);
}
export function setItem(key, value) {
localStorage.setItem(
key,
JSON.stringify({
storageId: generateUUID(),
value,
}),
);
}
export function removeItem(key) {
localStorage.removeItem(key);
}
export function getItem(key, remove = false) {
try {
const item = JSON.parse(localStorage.getItem(key));
if (remove) {
localStorage.removeItem(key);
}
return item;
} catch (e) {
const item = localStorage.getItem(key);
if (remove) {
localStorage.removeItem(key);
}
return item;
}
}
由于很多时候我们进行VUE
渲染的时候,需要获取到唯一的key
值,我这里给每一次的设置添加了唯一的KEY
值;除此之外,还有一个很关键的原因:
- 由于
storage
保存的数据都是字符串,监听事件的触发只有在跨页面
,值发生变化
,同源网站
的时候触发的。
我们打开2个页面,在页面加载完成之后,添加监听事件。
我们测试的时候可以在浏览器的控制台来修改localStorage
。
我们看看另外一个页面的控制台
这里事件监听的会把所有的数据传给你,连之前的旧值
也可以获取到。
在测试的时候,如果我们重复保存相同的值的时候,监听事件只能触发一次。
另外一个页面的控制台:
只输出了一次。
所以,我们在自己封装的API的时候,不用担心是否会出现相同的值触发不了的情况,因为我们每一次调用setItem
的时候都会生成一个唯一随机不重复的KEY
,这样就可以保证每次都能触发到。
事件的销毁
在页面或者dialog销毁的时候,记得要注销掉storage
的事件,因为你绑定在window
上,除了完全关闭页面之外,你的事件一定会一直存在的,并且在你第N次进入的时候,你就会发现监听事件会重复触发N次,因为你在window
添加了N次相同的事件。
如果你在mounted
上进行添加的话,你就要在destroed
事件进行销毁,如果你在弹出框显示的时候进行注册,你就需要在弹出框消失的时候注销掉这个事件。
父页面传值给子页面
这里我使用的是vue-router
来实现的,因为vue-router
支持路由传值,我们只需要在路由上添加我们需要传的值即可。其实原理还是通过window.href
来获取父页面的数据。
vue-router
配置方法:
[
{
name: 'home',
path: 'home',
meta: {
type: '父页面',
},
component: () => import('./home/index'),
},
{
name: 'alignmentEditIssue',
path: 'alignmentEditIssue/:id/:issueId',
meta: {
type: '子页面',
},
component: () => import('./alignmentEditIssue/index'),
},
];
const misionId = '123456'
const issueId = '563555'
window.open(`#/alignmentEditIssue/${misionId}/${issueId}`);
总结
storage
的兼容性基本全部平台的都支持了,除了使用storage
的方法之外,还可以使用websoket
,但是这个还需要在服务器进行管理,对于我们这个需求而言有点浪费,因为这里并不需要跨浏览器、跨用户通信。
更多推荐
所有评论(0)