vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > Vue3跨标签页通信

Vue3实现跨标签页通信的四种方式

作者:_Lok

在Vue应用中,跨标签页的通信通常涉及到两个或多个浏览器标签页之间的信息共享,由于每个标签页或窗口都是独立的JavaScript执行环境,它们不能直接通过Vue或其他JavaScript库来直接相互通信,但是,有一些方法可以实现这种跨标签页的通信,以下是一些常用的跨标签页通信方法

我们假设我们需求是需要新开一个页面,并且这两个页面需要通信,就可以使用到以下的通信方式

1. localStorage+storage事件

<!-- src/views/Home.vue -->
<template>
  <div>
    <h1>Home Page</h1>
  </div>
</template>

<script setup>
import { onMounted } from "vue";
onMounted(() => {
  // 标签页 Home:写入数据
  localStorage.setItem("message", "Home Page");
});
</script>

localStorage 是 HTML5 新增的一个会话存储对象,它允许网页在浏览器中存储键值对形式的数据,并且这些数据不会随着页面的关闭而消失,除非手动删除。

<!-- src/views/About.vue -->
<template>
  <div>
    <h1>About Page</h1>
  </div>
</template>

<script setup>
import { onMounted } from "vue";
onMounted(() => {
  // 标签页 About:监听变化
  window.addEventListener("storage", (event) => {
    if (event.key === "message") {
      console.log("收到消息:", event.newValue);
    }
  });
});
</script>

2. BroadcastChannel API

<!-- src/views/Home.vue -->
<template>
  <div>
    <h1>Home Page</h1>
    <el-button @click="sendMessage">发送消息</el-button>
  </div>
</template>

<script setup>
const sendMessage = () => {
  // 标签页 Home:发送消息
  //   1. 创建 BroadcastChannel 实例
  // 要使用 BroadcastChannel,首先需要创建一个 BroadcastChannel 实例,并指定一个频道名称。频道名称是一个字符串,用于标识不同的通信频道。这里的频道就是 "chat"。
  const channel = new BroadcastChannel("chat");

  //   2. 发送消息
  // 使用 postMessage 方法向指定频道发送消息。消息可以是任何可以序列化的数据类型,如字符串、对象、数组等。
  channel.postMessage("Home Message");
};
</script>
<!-- src/views/About.vue -->
<template>
  <div>
    <h1>About Page</h1>
  </div>
</template>

<script setup>
import { onMounted } from "vue";
onMounted(() => {
  const channel = new BroadcastChannel("chat");
  //   3. 接收消息
  // 通过监听 message 事件来接收其他上下文发送到该频道的消息。
  channel.onmessage = (event) => {
    console.log("收到消息:", event.data); // 监听消息
  };
});
</script>

3. WebSocket

<template>
  <div>
    <h1>WebSocket 示例</h1>
    <el-button @click="connectWebSocket">连接 WebSocket</el-button>
    <el-button @click="sendMessage" :disabled="!socket">发送消息</el-button>
    <el-button @click="closeWebSocket" :disabled="!socket">关闭连接</el-button>
    <ul>
      <li v-for="(message, index) in receivedMessages" :key="index">
        {{ message }}
      </li>
    </ul>
  </div>
</template>

<script setup>
import { ref } from "vue";

// 存储 WebSocket 实例
const socket = ref(null);
// 存储接收到的消息
const receivedMessages = ref([]);

// 连接 WebSocket
const connectWebSocket = () => {
  // 创建 WebSocket 实例,这里以 echo.websocket.org 为例,它是一个公共的 WebSocket 测试服务器,省去了自己搭建服务器的麻烦
  socket.value = new WebSocket("wss://echo.websocket.org");

  // WebSocket 连接成功时触发
  socket.value.onopen = () => {
    console.log("WebSocket 连接成功");
    receivedMessages.value.push("WebSocket 连接成功");
  };

  // 接收到服务器消息时触发
  socket.value.onmessage = (event) => {
    console.log("接收到消息:", event.data);
    receivedMessages.value.push(event.data);
  };

  // WebSocket 连接关闭时触发
  socket.value.onclose = () => {
    console.log("WebSocket 连接已关闭");
    receivedMessages.value.push("WebSocket 连接已关闭");
    socket.value = null;
  };

  // WebSocket 发生错误时触发
  socket.value.onerror = (error) => {
    console.error("WebSocket 发生错误:", error);
    receivedMessages.value.push("WebSocket 发生错误");
  };
};

// 发送消息到服务器
const sendMessage = () => {
  if (socket.value) {
    const message = "Hello, WebSocket!";
    socket.value.send(message);
    receivedMessages.value.push(`发送消息: ${message}`);
  }
};

// 关闭 WebSocket 连接
const closeWebSocket = () => {
  if (socket.value) {
    socket.value.close();
  }
};
</script>

4. SharedWorker

<template>
  <el-card>
    <template #header>
      <div class="card-header">SharedWorker 通信示例</div>
    </template>
    <el-button id="sendMessageButton" @click="sendMessage"
      >发送消息到 SharedWorker</el-button
    >
    <el-card v-if="response" style="margin-top: 20px">
      <template #header>
        <div>响应内容</div>
      </template>
      <div>{{ response }}</div>
    </el-card>
  </el-card>
</template>

<script setup>
import { ref, onMounted } from "vue";

// 创建 SharedWorker 实例,指定工作线程脚本文件路径
const worker = new SharedWorker("sharedWorker.js");

// 存储接收到的响应
const response = ref("");

const sendMessage = () => {
  const message = "Hello, SharedWorker!";
  // 向 SharedWorker 发送消息
  worker.port.postMessage(message);
  console.log("向 SharedWorker 发送消息:", message);
};

onMounted(() => {
  // 监听 SharedWorker 的消息事件
  worker.port.onmessage = function (event) {
    const newResponse = event.data;
    console.log("从 SharedWorker 接收到响应:", newResponse);
    // 更新响应内容
    response.value = newResponse;
  };

  // 启动端口通信
  worker.port.start();
});
</script>
// sharedWorker.js 文件,需要放在 public
// 创建一个消息通道,用于在不同上下文和工作线程之间通信
self.onconnect = function (e) {
  // 获取端口对象,用于接收和发送消息
  const port = e.ports[0];

  // 监听端口的消息事件
  port.onmessage = function (event) {
    const message = event.data;
    console.log("SharedWorker 接收到消息:", message);

    // 向发送消息的端口回复消息
    const response = `SharedWorker 已收到消息: ${message}`;
    port.postMessage(response);
  };
};

常见的跨标签页通信就是这四种,还有一些不常用的比如:postMessage ServiceWorker 要么比较复杂,要么有明显缺陷,在这里就不多展开。总结一下使用场景 👇

场景推荐方案原因
简单数据同步localStorage / BroadcastChannel轻量且无需服务器
实时通信BroadcastChannel / WebSocket事件驱动或服务器推送
跨域需求WebSocket支持跨域协议
复杂计算逻辑SharedWorker分担主线程压力
兼容性优先localStorage + WebSocket覆盖旧浏览器与跨域需求

以上就是Vue3实现跨标签页通信的四种方式的详细内容,更多关于Vue3跨标签页通信的资料请关注脚本之家其它相关文章!

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