【前端做不了!】打开新标签页创建成功,通知其他页面更新

浏览器标签页窗口通信

本文将为你介绍窗口通信使用场景、应用、实现

一、背景

产品: 前端,你这个创建页面需要新开标签页,然后创建成功,你这个本来的页面需要更新列表。

我: 前端做不了!

私下,稍加研究,看看怎么做,然后,下面给读者看看,我是如何做的。

二、窗口通信怎么做?

首先,非常感谢自己,因为在之前很喜欢阅读很多技术文章和视频,在之前就有看过一次分析两个窗口粒子效果。当时看了当中就提到浏览器是如何通信的。

因此,所以就结合自己的需求,似乎就刚刚满足,于是有了思路以后,就开始了解相关 API ,了解以后有三种实现方式,如下:

  • BroadcastChannel
  • SharedWorker
  • localStorage/sessionStorage

这里,我就看 BroadcastChannel 这个 API ,所以接下来我会根据他来实现。

因此就可以了解到,当你需要和我一样实现相同的场景,就可以联想到这就是窗口通信。

三、利用 BroadcastChannel 实现标签页通信

BroadcastChannel 接口代理了一个命名频道,可以让指定 origin 下的任意 browsing context 来订阅它。它允许同源的不同浏览器窗口,Tab 页,frame 或者 iframe 下的不同文档之间相互通信。通过触发一个 message 事件,消息可以广播到所有监听了该频道的 BroadcastChannel 对象。 查看MDN看更多

核心使用的方法:

  • BroadcastChannel.onmessage 事件处理器,用于定义当该对象上触发了 message 事件时要执行的函数。
  • BroadcastChannel.postMessage() 向所有监听了相同频道的 BroadcastChannel 对象发送一条消息,消息内容可以是任意类型的数据。

我本人使用的是 Vue 项目开发的,考虑到各位技术栈不同这里,这里我会分别实现 JsVueReact 的三种方式

3.1 Js 实现

这里封装 createBroadcastChannel

javascript 复制代码
const createBroadcastChannel = (channelName) => {
    // 创建
    const channel = new BroadcastChannel(channelName);
	
  	// 发送
    const sendMessage = (message) => {
        channel.postMessage(message);
    };
	
    // 处理接收
    const receiveMessage = (callback) => {
        channel.onmessage = (event) => {
            callback(event.data);
        };
    };
	
    // 关闭通信
    const close = () => {
        channel.close();
    };

    return {
        channel,
        sendMessage,
        receiveMessage,
        close,
    };
};

export default createBroadcastChannel;

如何使用

在 createBroadcastChannel01.html

html 复制代码
<body>
    <button>发送</button>
    <script src="./createBroadcastChannel.js"></script>
    <script>
        const { sendMessage } = createBroadcastChannel('test_channel');

        document.querySelector('button').addEventListener('click', () => {
            sendMessage('Hello World');
        });
    </script>
</body>

在 createBroadcastChannel02.html

html 复制代码
<body>
    <script src="./createBroadcastChannel.js"></script>
    <script>
        const { receiveMessage } = createBroadcastChannel('test_channel');

        receiveMessage((event) => {
            console.log('成功接收:' + event);
        })
    </script>
</body>

当我点击发送的时候,就会获得一下结果,如图

到这里,我们就已经知道当你在使用的时候,需要在设计到通信的页面创建相同的频道,保证通信一致,这样才能保证接收到正确的数据,即 createBroadcastChannel('test_channel') 这段代码。所以通信到这里,笔者跟着实现一遍就已经掌握。

3.2 Vue 实现

Vue 我会实现一个 Vue3 + Ts 的 hook ,代码如下:

ts 复制代码
import { onBeforeUnmount, onMounted, ref, type Ref } from "vue";

export interface UseBroadcastChannelReturn<D, P> {
  channel: Ref<BroadcastChannel | undefined>;
  data: Ref<D>;
  post: (data: P) => void;
  close: () => void;
  error: Ref<Event | null>;
}

export function useBroadcastChannel<D, P>(
  channelName: string
): UseBroadcastChannelReturn<D, P> {
  const channel = ref<BroadcastChannel>();
  const data = ref<D>();
  const error = ref<Event | null>(null);

  onMounted(() => {
    try {
      channel.value = new BroadcastChannel(channelName);
      channel.value.onmessage = event => {
        data.value = event.data;
      };
    } catch (e) {
      error.value = e;
    }
  });

  onBeforeUnmount(() => {
    close();
  });

  const post = (data: P) => {
    if (channel.value) {
      channel.value.postMessage(data);
    }
  };

  const close = () => {
    if (channel.value) {
      channel.value.close();
    }
  };

  return {
    channel,
    data,
    post,
    close,
    error
  };
}

3.3 React 实现

我会实现ReactReact + Ts 的 hook ,代码如下:

ts 复制代码
import React, { useEffect, useRef, useState } from 'react';

export interface UseBroadcastChannelReturn<D, P> {
 channel: BroadcastChannel | undefined;
 data: D | undefined;
 post: (data: P) => void;
 close: () => void;
 error: Event | null;
}

export function useBroadcastChannel<D, P>(
 channelName: string
): UseBroadcastChannelReturn<D, P> {
 const [channel, setChannel] = useState<BroadcastChannel | undefined>();
 const [data, setData] = useState<D>();
 const [error, setError] = useState<Event | null>(null);
 const channelRef = useRef<BroadcastChannel>();

 useEffect(() => {
   try {
     const newChannel = new BroadcastChannel(channelName);
     newChannel.onmessage = (event) => {
       setData(event.data);
     };
     channelRef.current = newChannel;
     setChannel(newChannel);
   } catch (e) {
     setError(e);
   }
   
   return () => {
     close();
   };
 }, [channelName]);

 const post = (dataToSend: P) => {
   if (channelRef.current) {
     channelRef.current.postMessage(dataToSend);
   }
 };

 const close = () => {
   if (channelRef.current) {
     channelRef.current.close();
   }
 };

 return {
   channel,
   data,
   post,
   close,
   error
 };
}

不管是 Vue 还是 React 使用方式都参考 Js 的方式,返回了 channel 是方便使用更多的 API

四、总结

到这里就结束了,我们讨论了窗口通信是怎么做的。以及在什么场景下会使用到。BroadcastChannel 是一个非常强大的API,帮助我实现了标签页的通信。希望这篇文章能帮助到你,就像我曾经也被其他笔者帮助一样,我只是将这份热爱传递下去,感谢您阅读到最后,下期再见。

相关推荐
狗头大军之江苏分军13 分钟前
iPhone 17 vs iPhone 17 Pro:到底差在哪?买前别被忽悠了
前端
小林coding13 分钟前
再也不怕面试了!程序员 AI 面试练习神器终于上线了
前端·后端·面试
文心快码BaiduComate26 分钟前
WAVE SUMMIT深度学习开发者大会2025举行 文心大模型X1.1发布
前端·后端·程序员
babytiger26 分钟前
python 通过selenium调用chrome浏览器
前端·chrome
passer98132 分钟前
基于webpack的场景解决
前端·webpack
奶昔不会射手1 小时前
css3之grid布局
前端·css·css3
举个栗子dhy1 小时前
解决在父元素上同时使用 onMouseEnter和 onMouseLeave时导致下拉菜单无法正常展开或者提前收起问题
前端·javascript·react.js
Coding_Doggy1 小时前
苍穹外卖前端Day1 | vue基础、Axios、路由vue-router、状态管理vuex、TypeScript
前端