前端多tab共享多状态,且满足tab or 浏览器关闭时清除当前状态

79 阅读1分钟

场景:

三组开关按钮 分别是 [上班/下班] [工作/休息] [派单/停止]

有三个窗口要能共享上班 工作两个状态,且有派单就不能点击休息,必须关闭所有派单

image.png

状态解读

当前状态变为【xx】时:

【上班】 => work: true,assign: ture, [工作/休息] => 休息, 「 派单/停止」 => 停止

【下班】 => work: false,assign: false[工作/休息] => 工作, 「 派单/停止」 => 派单

窗口>=1时,需要把所有的【派单】状态改为【派单】,才可以点击休息。

方案设计

1、 BroadcastChannel 发送消息,实现不同窗口之间共享数据

2、 localstroage 存储窗口信息

3、 window.addEventListener(unload)负责删除窗口关闭的数据。

为什么不使用SeesionStorage

只存在于当前tab页 -----数据无法共享给同域名其他的tab

为什么不只使用LocalStorage

当有tab页关闭,localStorage中的数据不会被删除 ---需要当前窗口的数据被删除

代码实现

// 1 编写BroadcastChannel hook
export const useBroadcastChannel = ({
 channelName,
 onMessage,
}: UseBroadcastChannelParams) => {
 useEffect(() => {
   if (onMessage) {
     const channel = new BroadcastChannel(channelName);
     channel.onmessage = (event) => {
       onMessage(event.data);
     };
     return () => {
       channel.close();
     };
   }
 }, [channelName, onMessage]);

 const postMessage = (data: any) => {
   const channel = new BroadcastChannel(channelName);
   channel.postMessage(data);
   channel.close();
 };

 return { postMessage };
};

// 2、在需要的地方注册发送者
const { postMessage } = useBroadcastChannel({
 channelName: 'currentWorkStatusChannel',
});

postMessage({type,status})

// 3、接受消息 更新其他窗口的状态
useBroadcastChannel({
 channelName: 'currentWorkStatusChannel',
 onMessage:(data) => {
     const {type,status} = data;
     switch(type) {
         '上班':
         ....
         break;
         '休息':
         ...
         break;
         default:
     }
 }
});

// 4、unload
const onUnload = () => {
 setTab(xx, false);
};

// 检测关闭窗口时的状态切换
useEffect(() => {
 window.addEventListener('unload', onUnload);
 return () => {
   window.removeEventListener('unload', onUnload);
 };
}, []);

// 5、localStorge设置
const getTab = () => {
 try {
   const keys = localStorage.getItem('TAB');
   return keys ? JSON.parse(keys) : [];
 } catch (e) {
   return [];
 }
};

export const hasNotQueue = () => getTab().length === 0;

/**
* @param id
* @param status 添加还是删除
*/
export const setWorkQueue = (id: string | number, status: boolean) => {
 const keys = getTab();
 if (!status) {
   localStorage.setItem(
     'TAB',
     JSON.stringify(keys.filter((key: string | number) => key !== id)),
   );
   return;
 }
 if (keys.includes(id)) {
   return;
 }

 localStorage.setItem('TAB', JSON.stringify([...keys, id]));
};