javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > JS BroadcastChannel浏览器标签页通信

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

作者:Lewiis

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

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

window.open()实现

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

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

BroadcastChannel实现

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

实现过程

创建两个路由页面

列表页

<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区别

相同点:

不同点:

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浏览器标签页通信内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文