JS中BroadcastChannel实现浏览器标签页通信

 更新时间:2025年10月21日 10:02:51   作者:Lewiis  
浏览器标签页通信常用于列表页进入详情页所进行的标签页间通信的情况,实际使用例如博客页面的列表和文章编辑页面、音乐网站的列表和音乐播放详情等,本文就来详细的介绍一下BroadcastChannel实现浏览器标签页通信,感兴趣的可以了解一下

浏览器标签页通信常用于列表页进入详情页所进行的标签页间通信的情况,实际使用例如博客页面的列表和文章编辑页面、音乐网站的列表和音乐播放详情等。

window.open()实现

使用常用的window.open()API也可以实现,但会存在以下问题:

  1. 打开新页面时浏览器标签页焦点也会跳转到新页面(如果没有标签页焦点不变的需求可以忽略不计);
  2. 打开新页面导致新页面全局刷新(多页应用或跳转的新页面内容较少可忽略不计);

BroadcastChannel实现

BroadcastChannel 是 Web API 里用于在同源的不同浏览器上下文(像不同的窗口、标签页、iframe 等)间进行通信的机制,因此可以规避以上两个问题:

实现过程

创建两个路由页面

  • 列表页 /
  • 详情页/detail

列表页

<template>
  <div class="table-box">
    <el-table :data="tableData" style="width: 100%">
      <el-table-column prop="username" label="用户名" />
      <el-table-column prop="sex" label="性别" />
      <el-table-column fixed="right" label="操作" min-width="120">
        <template #default="scope">
          <el-button
            link
            type="primary"
            size="small"
            @click="handleClick(scope.row)"
          >
            详情
          </el-button>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>

<script setup>
import { ref } from "vue";
import { userList } from "@/utils/data";
const handleClick = async (row) => {
  // channel通信
  const channel = new BroadcastChannel("user_detail");
  const tabCount = localStorage.getItem("TAB_COUNT");
  if (!tabCount || tabCount === "1") {
    await localStorage.setItem("TAB_COUNT", "2");
    await sessionStorage.setItem("TAB_ID", row.id);
    window.open("/detail", "user_detail");
  } else {
    channel.postMessage(row.id);
  }
};

const tableData = ref(userList);
</script>

详情页

<template>
  <el-descriptions
    class="margin-top"
    title="用户信息表"
    :column="3"
    size="large"
    border
  >
    <template #extra>
      <el-button type="primary" @click="goBack">返回</el-button>
    </template>
    <el-descriptions-item>
      <template #label>
        <div class="cell-item">
          <el-icon :style="iconStyle">
            <user />
          </el-icon>
          用户名
        </div>
      </template>
      {{ curUser.username }}
    </el-descriptions-item>
    <el-descriptions-item>
      <template #label>
        <div class="cell-item">
          <el-icon :style="iconStyle">
            <iphone />
          </el-icon>
          年龄
        </div>
      </template>
      {{ curUser.age }}
    </el-descriptions-item>
    <el-descriptions-item>
      <template #label>
        <div class="cell-item">
          <el-icon :style="iconStyle">
            <location />
          </el-icon>
          籍贯
        </div>
      </template>
      {{ curUser.city }}
    </el-descriptions-item>
    <el-descriptions-item>
      <template #label>
        <div class="cell-item">
          <el-icon :style="iconStyle">
            <tickets />
          </el-icon>
          性别
        </div>
      </template>
      {{ curUser.sex }}
    </el-descriptions-item>
    <el-descriptions-item>
      <template #label>
        <div class="cell-item">
          <el-icon :style="iconStyle">
            <office-building />
          </el-icon>
          住址
        </div>
      </template>
      {{ curUser.address }}
    </el-descriptions-item>
  </el-descriptions>
</template>

<script setup>
import { ref, onMounted } from "vue";
import { useRoute } from "vue-router";
import { userList } from "@/utils/data";

const route = useRoute();
const initialUser = {
  date: "",
  username: "",
  sex: "",
  age: 18,
  city: "",
  address: "",
  id: "",
};
const curUser = ref({ ...initialUser });
const goBack = async () => {
  await localStorage.setItem("TAB_COUNT", "1");
  await sessionStorage.removeItem("TAB_ID");
  window.close();
};
const iconStyle = {
  fontSize: "20px",
  color: "#409eff",
};

const channel = new BroadcastChannel("user_detail");
channel.addEventListener("message", (event) => {
  console.log("接收到消息:", event.data);
  sessionStorage.removeItem("TAB_ID");
  const curUserId = event.data;
  const user = userList.find((user) => user.id === curUserId);
  if (user) {
    curUser.value = user;
  }
});

onMounted(() => {
  const curUserId = sessionStorage.getItem("TAB_ID");
  if (curUserId) {
    const user = userList.find((user) => user.id === curUserId);
    if (user) {
      curUser.value = user;
    }
  }
  // 监听页面卸载事件
  window.addEventListener("unload", async () => {
    await localStorage.setItem("TAB_COUNT", "1");
    await sessionStorage.removeItem("TAB_ID");
  });
});
</script>

实现效果

实现原理

使用BroadcastChannel创建通道进行浏览器标签页通信,利用浏览器本地缓存记录标签页打开数量,如果数量为1(仅有列表页,没有详情页),则使用window.open打开;反之如果数量为2,则使用BroadcastChannel通道发送消息实现页面数据更新;

BroadcastChannel和postMessage区别

相同点:

  • 都可在不同页面之间,进行信息通讯

不同点:

  • BroadcastChannel只可用于同源的不同页面;
  • postmessage可以任何源

1.BroadcastChannel使用方法

// 实例BroadcastChannel
const myChannel = new BroadcastChannel('aa');
// 发送信息
myChannel.postMessage('发送的某些数据');
myChannel.onmessage = function(e){
    // 接收到的消息
    console.log(e.data);
}
// 关闭链接
myChannel.close();

2.postMessage使用方法

//给其他源发送postMessage
otherWindow.postMessage(message, targetOrigin, [transfer]);
****解释********
otherWindow:其他窗口的一个引用,比如 iframe 的 contentWindow 属性、执行 window.open 返回的窗口对象、或者是命名过或数值索引的 window.frames
message:将要发送到其他 window的数据。
targetOrigin:指定哪些窗口能接收到消息事件,其值可以是 *(表示无限制)或者一个 URI。
transfer:可选,是一串和 message 同时传递的 Transferable 对象。这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。
*****************
// 其他源的页面,添加addEventlistener监听message
window.addEventListener('message', function (e) {  // 监听 message 事件
        messageEle.innerHTML = "从"+ e.origin +"收到消息: " + e.data;
    });

到此这篇关于JS中BroadcastChannel实现浏览器标签页通信的文章就介绍到这了,更多相关JS BroadcastChannel浏览器标签页通信内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • JavaScript中通用的jquery动画滚屏实例

    JavaScript中通用的jquery动画滚屏实例

    这篇文章主要介绍了JavaScript中通用的jquery动画滚屏实例,本文通过实际代码来详解实现方法,需要的朋友可以参考一下
    2022-07-07
  • JS实现的颜色实时渐变效果完整实例

    JS实现的颜色实时渐变效果完整实例

    这篇文章主要介绍了JS实现的颜色实时渐变效果,结合实例形式分析了JavaScript结合时间函数定时触发动态改变页面元素属性的相关技巧,需要的朋友可以参考下
    2016-03-03
  • 常规表格多表头查询示例

    常规表格多表头查询示例

    这篇文章主要介绍了常规表格多表头查询,需要的朋友可以参考下
    2014-02-02
  • 微信小程序实现日历签到

    微信小程序实现日历签到

    这篇文章主要为大家详细介绍了微信小程序实现日历签到功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-09-09
  • js Proxy的原理详解

    js Proxy的原理详解

    Proxy用于修改某些操作的默认行为,在目标对象前架设一个“拦截”层,外界对该对象的访问都必须先通过这一层拦截,因此提供了一种机制可以对外界的访问进行过滤和改写。本文就讲讲Proxy的使用
    2021-05-05
  • js设计模式之结构型享元模式详解

    js设计模式之结构型享元模式详解

    这篇文章主要为大家详细介绍了js设计模式之结构型享元模式的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-09-09
  • JavaScript阻止浏览器返回按钮的方法

    JavaScript阻止浏览器返回按钮的方法

    这篇文章主要介绍了JavaScript阻止浏览器返回按钮的方法,可实现通过javascript禁用掉返回按钮的功能,需要的朋友可以参考下
    2015-03-03
  • 跟我学Nodejs(三)--- Node.js模块

    跟我学Nodejs(三)--- Node.js模块

    这是本系列的第三篇文章了,前面2篇网友们反馈回来不少的消息,加上最近2天比较忙,一直没来得及整理,周末了,赶紧给大家整理下发出来,本文讲的是node.js模块
    2014-05-05
  • JavaScript this关键字的深入详解

    JavaScript this关键字的深入详解

    这篇文章主要给大家介绍了关于JavaScript this关键字的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • Javascript中查找不以XX字符结尾的单词示例代码

    Javascript中查找不以XX字符结尾的单词示例代码

    我在写这篇文章之前花了2个多小时在弄正则表达式,下为大家介绍下具体的实现思路,感兴趣的朋友可以参考下
    2013-10-10

最新评论