VUE中使用localStorage实现跨标签页面的通信

it2026-08-03  13

前言

目前出现了一个需求,需要父页面打开新的子页面,子页面提交表单之后,关闭子页面,然后把数据返回给父页面。 本来考虑使用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)