前端跨页面交互信息或传递信息都有这么几种方式,总有一个满足你的使用场景

同源页面通信:

方法:Broadcast Channel 【广播】

这个可以查看我另一篇文章有使用案例

同一来源的不同文档(在不同的窗口、选项卡、框架或 iframe 中)之间进行通信

// page1<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>page1</title>
</head>
<body><button onclick="sendMessage()">发广播</button><button onclick="closeBroadcast()">关闭广播</button><button onclick="openBroadcast()">开启广播</button>
</body>
</html><script>let bc = null;// 开启广播function openBroadcast() {console.log('开启广播');bc = new BroadcastChannel('cctv');// 接收广播bc.onmessage = function(e) {alert(e.data);};// 异常处理bc.onmessageerror = function(e) {console.warn('onmessageerror');};}openBroadcast();// 关闭广播function closeBroadcast() {console.log('关闭广播');bc.close();}// 发消息function sendMessage() {bc.postMessage('page1: 咯咯')}
</script>
// page2<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>page2</title>
</head>
<body><button onclick="sendMessage()">发广播</button><button onclick="closeBroadcast()">关闭广播</button><button onclick="openBroadcast()">开启广播</button>
</body>
</html><script>let bc = null;// 开启广播function openBroadcast() {console.log('开启广播');bc = new BroadcastChannel('cctv');// 接收广播bc.onmessage = function(e) {alert(e.data);};// 异常处理bc.onmessageerror = function(e) {console.warn('onmessageerror');};}openBroadcast();// 关闭广播function closeBroadcast() {console.log('关闭广播');bc.close();}// 发消息function sendMessage() {bc.postMessage('page2: 哒~')}
</script>

Service Worker 【广播】

// page1<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>page1</title>
</head>
<body><button onclick="sendMessage()">发广播</button><p></p>
</body>
</html><script>navigator.serviceWorker.register('sw.js').then(function () {console.log('Service Worker 注册成功');})navigator.serviceWorker.addEventListener('message', function (e) {const { data } = e;// 过滤自己发送的消息if (data.from !== 'page1') {document.querySelector('p').innerText = `${data.from}:${data.data}`;}});function sendMessage() {const msg = {from: 'page1',data: '咯咯'}navigator.serviceWorker.controller.postMessage(msg);}
</script>
// page2<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>page2</title>
</head>
<body><button onclick="sendMessage()">发广播</button><p></p>
</body>
</html><script>navigator.serviceWorker.register('sw.js').then(function () {console.log('Service Worker 注册成功');})navigator.serviceWorker.addEventListener('message', function (e) {const { data } = e;// 过滤自己发送的消息if (data.from !== 'page2') {document.querySelector('p').innerText = `${data.from}:${data.data}`;}});function sendMessage() {const msg = {from: 'page2',data: '哒~'}navigator.serviceWorker.controller.postMessage(msg);}
</script>
// sw.jsself.addEventListener('message', function (e) {console.log('service worker receive message', e.data);e.waitUntil(self.clients.matchAll().then(function (clients) {if (!clients || clients.length === 0) {return;}clients.forEach(function (client) {client.postMessage(e.data);});}));
});

localStorage 【共享存储 + 监听】

// page1<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>page1</title>
</head>
<body><button onclick="sendMessage()">发广播</button><button onclick="closeBroadcast()">关闭广播</button><button onclick="openBroadcast()">开启广播</button>
</body>
</html><script>function handleMessage(e) {if (e.key === 'localMessage') {const msg = JSON.parse(e.newValue);alert(msg.data);}}// 开启广播function openBroadcast() {console.log('开启广播');// 在当前页面setItem,storage事件不会触发,另外开个标签页,可以在另一个标签页中触发window.addEventListener('storage', handleMessage);}openBroadcast();// 关闭广播function closeBroadcast() {console.log('关闭广播');window.removeEventListener('storage', handleMessage)}// 发消息function sendMessage() {const msg = {data: 'page1: 咯咯',stamp: new Date()}// 设置相同的内容,storage不会触发,用时间戳解决window.localStorage.setItem('localMessage', JSON.stringify(msg));}
</script>
<!DOCTYPE html>
// page2<html lang="en">
<head><meta charset="UTF-8"><title>page2</title>
</head>
<body><button onclick="sendMessage()">发广播</button><button onclick="closeBroadcast()">关闭广播</button><button onclick="openBroadcast()">开启广播</button>
</body>
</html><script>function handleMessage(e) {if (e.key === 'localMessage') {const msg = JSON.parse(e.newValue);alert(msg.data);}}// 开启广播function openBroadcast() {console.log('开启广播');// 在当前页面setItem,storage事件不会触发,另外开个标签页,可以在另一个标签页中触发window.addEventListener('storage', handleMessage);}openBroadcast();// 关闭广播function closeBroadcast() {console.log('关闭广播');window.removeEventListener('storage', handleMessage)}// 发消息function sendMessage() {const msg = {data: 'page2: 哒~',stamp: new Date()}// 设置相同的内容,storage不会触发,用时间戳解决window.localStorage.setItem('localMessage', JSON.stringify(msg));}
</script>

Shared Worker 【共享存储 + 轮询】

无法主动通知,需要轮询获取最新数据

// page1<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>page1</title>
</head>
<body>
<button onclick="sendMessage()">发广播</button>
<button onclick="closeBroadcast()">关闭广播</button>
<button onclick="openBroadcast()">开启广播</button>
</body>
</html><script>let worker = null;let timer = null;// 开启广播function openBroadcast() {console.log('开启广播');worker = new SharedWorker("sharedWorker.js", 'messageWorker'); // [https://developer.mozilla.org/zh-CN/docs/Web/API/SharedWorker/SharedWorker]// 定时轮询,发送 get 指令的消息timer = setInterval(function () {worker.port.postMessage({ get: true });}, 1000);// 监听 get 消息的返回数据worker.port.onmessage = function (e) {console.log(e.data);}}openBroadcast();function closeBroadcast() {console.log('关闭广播');clearInterval(timer);}// 发消息function sendMessage() {worker.port.postMessage('page1: 咯咯');}
</script>
// page2<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>page2</title>
</head>
<body><button onclick="sendMessage()">发广播</button><button onclick="closeBroadcast()">关闭广播</button><button onclick="openBroadcast()">开启广播</button>
</body>
</html><script>let worker = null;let timer = null;// 开启广播function openBroadcast() {console.log('开启广播');worker = new SharedWorker("sharedWorker.js", 'messageWorker'); // [https://developer.mozilla.org/zh-CN/docs/Web/API/SharedWorker/SharedWorker]// 定时轮询,发送 get 指令的消息timer = setInterval(function () {worker.port.postMessage({ get: true });}, 1000);// 监听 get 消息的返回数据worker.port.addEventListener('message', (e) => {console.log(e.data);}, false);// addEventListener监听时要手动开始,onmessage时不需要worker.port.start();}openBroadcast();function closeBroadcast() {console.log('关闭广播');clearInterval(timer);}// 发消息function sendMessage() {worker.port.postMessage('page2: 哒~');}
</script>
// sharedWorker.js
let data = null;self.addEventListener('connect', function (e) {const port = e.ports[0];port.addEventListener('message', function (event) {// get 指令则返回存储的消息数据if (event.data.get) {data && port.postMessage(data);}// 非 get 指令则存储该消息数据else {data = event.data;}});port.start();
});

window.opener 【口口相传】

// page1<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>page1</title>
</head>
<body><button onclick="sendMessage()">发广播</button><button onclick="closeBroadcast()">关闭广播</button><button onclick="openBroadcast()">开启广播</button>
</body>
</html><script>let wins = []; // 记录打开的子窗口const openedWin = window.open('page2.html')wins.push(openedWin);// 发广播function sendMessage() {const openingWins = wins.filter(item => !item.closed); // 过滤已被关闭的页面// 向子级窗口发送消息if (openingWins.length) {const msg = {data: 'page1: 咯咯',upMsg: false,         // 是否向上级窗口发送的消息}openingWins.forEach(item => item.postMessage(msg))}// 有父级窗口,向父级窗口发消息if (window.opener && !window.opener.closed) {const msg = {data: 'page1: 咯咯',upMsg: true,         // 是否向上级窗口发送的消息}window.opener.postMessage(msg);}}// 开启广播function openBroadcast() {window.addEventListener('message', function (e) {const { data, upMsg } = e.data;alert(data);// 收到向上传递的消息,有父级窗口,继续向上传递if (window.opener && !window.opener.closed && upMsg) {window.opener.postMessage(e.data);}const openingWins = wins.filter(item => !item.closed); // 过滤已被关闭的页面// 收到向下传递的消息,有子级窗口,继续向下传递if (openingWins.length && !upMsg) {openingWins.forEach(item => item.postMessage(e.data))}});}openBroadcast()// 关闭广播function closeBroadcast() {// TODO}
</script>
// page2<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>page2</title>
</head>
<body><button onclick="sendMessage()">发广播</button><button onclick="closeBroadcast()">关闭广播</button><button onclick="openBroadcast()">开启广播</button>
</body>
</html><script>let wins = []; // 记录打开的子窗口const openedWin = window.open('page3.html')wins.push(openedWin);// 发广播function sendMessage() {const openingWins = wins.filter(item => !item.closed); // 过滤已被关闭的页面// 向子级窗口发送消息if (openingWins.length) {const msg = {data: 'page2: 咯咯',upMsg: false,         // 是否向上级窗口发送的消息}openingWins.forEach(item => item.postMessage(msg))}// 有父级窗口,向父级窗口发消息if (window.opener && !window.opener.closed) {const msg = {data: 'page2: 咯咯',upMsg: true,         // 是否向上级窗口发送的消息}window.opener.postMessage(msg);}}function openBroadcast() {window.addEventListener('message', function (e) {const { data, upMsg } = e.data;alert(data);// 收到向上传递的消息,有父级窗口,继续向上传递if (window.opener && !window.opener.closed && upMsg) {window.opener.postMessage(e.data);}const openingWins = wins.filter(item => !item.closed); // 过滤已被关闭的页面// 收到向下传递的消息,有子级窗口,继续向下传递if (openingWins.length && !upMsg) {openingWins.forEach(item => item.postMessage(e.data))}});}openBroadcast()// 关闭广播function closeBroadcast() {// TODO}
</script>
// page3<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>page3</title>
</head>
<body><button onclick="sendMessage()">发广播</button><button onclick="closeBroadcast()">关闭广播</button><button onclick="openBroadcast()">开启广播</button>
</body>
</html><script>let wins = []; // 记录打开的子窗口// 发广播function sendMessage() {const openingWins = wins.filter(item => !item.closed); // 过滤已被关闭的页面// 向子级窗口发送消息if (openingWins.length) {const msg = {data: 'page3: 咯咯',upMsg: false,         // 是否向上级窗口发送的消息}openingWins.forEach(item => item.postMessage(msg))}// 有父级窗口,向父级窗口发消息if (window.opener && !window.opener.closed) {const msg = {data: 'page3: 咯咯',upMsg: true,         // 是否向上级窗口发送的消息}window.opener.postMessage(msg);}}function openBroadcast() {window.addEventListener('message', function (e) {const { data, upMsg } = e.data;alert(data);// 收到向上传递的消息,有父级窗口,继续向上传递if (window.opener && !window.opener.closed && upMsg) {window.opener.postMessage(e.data);}const openingWins = wins.filter(item => !item.closed); // 过滤已被关闭的页面// 收到向下传递的消息,有子级窗口,继续向下传递if (openingWins.length && !upMsg) {openingWins.forEach(item => item.postMessage(e.data))}});}openBroadcast()// 关闭广播function closeBroadcast() {// TODO}
</script>

非同源页面通信

iframe 【代理】
父A = 非同源应用A (e.g. http://localhost:63342/demo/iframe/page1.html)
子A = 非同源iframe桥(e.g. http://localhost:8081/)

父B = 非同源应用B (e.g. http://192.168.2.112:3000/)
子B = 非同源iframe桥 (e.g. http://localhost:8081/)

1. 所有消息都先发给iframe桥

const bridgeIframe = document.getElementById('bridgeIframe');
const msg = {type: 'bridge-msg',data: 'page1: 咯咯'
};
bridgeIframe.contentWindow.postMessage(msg, '*');
// window.frames[0].window.postMessage(msg, '*');

2. iframe接收后发起同源广播,同源广播可以在另一个应用中监听

// 接收iframe消息
window.addEventListener('message', (e) => {const { data } = e;// 转发消息,消息会进入另一个跨域应用的iframe桥的bc.onmessage中if (data.type === 'bridge-msg') {this.bc.postMessage(`${data.data}`)}
});

3. iframe通过窗口对象转发消息

window.parent.postMessage(e.data, '*');

完整代码:

// page1 纯html页面,webstorm服务器运行<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>page1</title>
</head>
<body><span></span><button onclick="sendMessage()">发广播</button>
</body>
</html><script>// 发消息function sendMessage() {const bridgeIframe = document.getElementById('bridgeIframe');const msg = {type: 'bridge-msg',data: '咯咯'};bridgeIframe.contentWindow.postMessage(msg, '*');}// 创建桥梁function createBridge() {const bridgeIframe = document.createElement('iframe');bridgeIframe.setAttribute('id', 'bridgeIframe');// bridgeIframe.style.display = 'none';bridgeIframe.src = 'http://localhost:8081/';document.body.appendChild(bridgeIframe);}createBridge();// 监听iframe桥发来的消息window.addEventListener('message', function(e) {const { data, origin } = e;document.querySelector('span').innerText = `${origin}: ${data}`;});
</script>
// bridgeIframe Vue2应用 http://localhost:8081/<button @click="sendMessage">发广播</button><script>export default {name: 'App',data() {return {bc: null,}},methods: {// 开启广播openBroadcast() {this.bc = new BroadcastChannel('cctv');// 接收广播// bc广播是同源广播,因为两个跨域应用this.bc.onmessage = (e) => {console.log(`iframe桥接收到的消息:${e.data}`);window.parent.postMessage(e.data, '*');};// 异常处理this.bc.onmessageerror = function(e) {console.warn('onmessageerror');};}},mounted() {this.openBroadcast();// 接收iframe消息window.addEventListener('message', (e) => {const { data } = e;// 转发消息,消息会进入另一个跨域应用的iframe桥的bc.onmessage中if (data.type === 'bridge-msg') {this.bc.postMessage(`${data.data}`)}});}}
</script>
// page2 React应用 http://192.168.2.112:3000import './App.css';
import { useEffect, useState } from "react";function App() {const [msg, setMsg] = useState('');useEffect(() => {createBridge();// 监听iframe桥发来的消息window.addEventListener('message', function (e) {const { data, origin } = e;setMsg(`${origin}: ${data}`);});}, [])// 创建桥梁const createBridge = () => {const bridgeIframe = document.createElement('iframe');bridgeIframe.setAttribute('id', 'bridgeIframe');// bridgeIframe.style.display = 'none';bridgeIframe.src = 'http://localhost:8081/';document.body.appendChild(bridgeIframe);}// 发消息const sendMessage = () => {const bridgeIframe = document.getElementById('bridgeIframe');const msg = {type: 'bridge-msg',data: '哒~'};bridgeIframe.contentWindow.postMessage(msg, '*');}return (<div className="App">{ msg }<button onClick={sendMessage}>发广播</button></div>);
}export default App;

参考文章:面试官:前端跨页面通信,你知道哪些方法? - 掘金

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/240359.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

(1)(1.9) MSP (version 4.2)

文章目录 前言 1 协议概述 2 配置 3 参数说明 前言 ArduPilot 支持 MSP 协议&#xff0c;可通过任何串行端口进行遥测、OSD 和传感器。这样&#xff0c;ArduPilot 就能将遥测数据发送到 MSP 兼容设备&#xff08;如大疆护目镜&#xff09;&#xff0c;用于屏幕显示&#x…

(C)一些题15

1.下列关于 C 语言程序结构的说法中&#xff0c;不正确的是&#xff08;D) A &#xff0e;一个程序由一个或多个源程序文件组成 B &#xff0e;函数是 C 程序的主要组成部分 C &#xff0e;程序总是从 main 函数开始执行的 D . C 语言本身提供了许多输入输出语句 解析&…

【Java基础】01- 基础概念

注释和关键字 注释 定义&#xff1a;代码中需要一些解释说明性的文字&#xff0c;通常称为注释。 单行注释&#xff1a; // 注释信息多行注释&#xff1a;/* 注释信息 */文档注释&#xff1a;/** 注释信息 */ 文档注释可以利用Java中自带的DOC工具&#xff0c;自动生成相关代…

银河麒麟v10 安装mysql 8.35

银河麒麟v10 安装mysql 8.35 1、卸载mariadb2、下载Mysql安装包3、安装Mysql 8.353.1、安装依赖包3.2、安装Mysql3.3、安装后配置 1、卸载mariadb 由于银河麒麟v10系统默认安装了mariadb 会与Mysql相冲突&#xff0c;因此首先需要卸载系统自带的mariadb 查看系统上默认安装的M…

MyBatis动态SQL中if,where,set,trim四种标签的使用和联系

目录 MyBatis动态SQL中if&#xff0c;where&#xff0c;set&#xff0c;trim四种标签的使用和联系1、先介绍trim标签以下是trim标签中涉及到的属性&#xff1a; 2、使用trim标签或where标签去除多余的and关键字3、使用trim标签或set标签去除多余的逗号 MyBatis动态SQL中if&…

前端常用的开发工具

前端常用的开发工具&#x1f516; 文章目录 前端常用的开发工具&#x1f516;1. Snipaste--截图工具2. ScreenToGif--gif图片录制3. Typora--Markdown编辑器4. notepad--文本代码编辑器5. uTools--多功能工具6. EV录屏--录屏软件7. Xmind--思维导图8. Apifox -- 接口调试9. Tor…

【大数据】NiFi 中的 Controller Service

NiFi 中的 Controller Service 1.Service 简介1.1 Controller Service 的配置1.1.1 SETTING 基础属性1.1.2 PROPERTIES 使用属性1.1.3 COMMENT 页签 1.2 Service 的使用范围 2.全局参数配置3.DBCPConnectionPool 的使用样例4.在 ExcuseGroovyScript 组件中使用 Service 1.Servi…

记一次 Nginx 调参的踩坑经历

最近在基于SSE&#xff08;Server Sent Events&#xff09;做服务端单向推送服务&#xff0c;本地开发时一切顺利&#xff0c;但是在部署到预发环境时就碰到1个很诡异的问题&#xff0c;这里需要简单介绍下我们的整体架构&#xff1a; 整体架构 可以看到所有的请求都会先到统一…

2024 年 22 款顶级免费数据恢复软件比较 [Windows 和 Mac]

适用于 Windows 和 Mac 用户的最佳数据恢复软件下载列表和比较&#xff0c;可快速恢复丢失的数据、已删除的文件、照片或格式化的分区数据&#xff1a; 数据恢复软件是一种从任何存储介质恢复丢失文件的应用程序。它可以恢复由于病毒攻击、硬盘故障或任何其他原因而意外删除或…

NIO的实战教程(简单且高效)

1. 参考 建议按顺序阅读以下三篇文章 为什么NIO被称为同步非阻塞&#xff1f; Java IO 与 NIO&#xff1a;高效的输入输出操作探究 【Java.NIO】Selector&#xff0c;及SelectionKey 2. 实战 我们将模拟一个简单的HTTP服务器&#xff0c;它将响应客户端请求并返回一个固定的…

Wails中js调用go函数(1种go写法,2种js调用方法)

官方js调用go方法文档&#xff1a;https://wails.io/zh-Hans/docs/howdoesitwork a&#xff09;在app.go文件里写一个要js调用的go函数&#xff1a; func (a *App) JSCallGo(data1 string) string { return “test” } b&#xff09;运行 wails dev 命令&#xff0c…

Maven核心概念

1 Maven工程的GAVP Maven 中的 GAVP 是指 GroupId、ArtifactId、Version、Packaging 等四个属性的缩写&#xff0c;其中前三个是必要的&#xff0c;而 Packaging 属性为可选项。 这四个属性主要为每个项目在maven仓库中做一个标识&#xff0c;方便项目之间相互引用。 GAV G 即…

54.0/CSS 样式属性(详细版)

目录 54.1 文本属性 54.1.1 设置字体——font-family 54.1.2 设置字号(font-size)和字的颜色(color) 54.1.3 设置字体加粗——font-weight 54.1.4 添加文字修饰——text-decoration 54.1.5 设置文本排列方式——text-align 54.1.6 设置段落首行缩进——text-indent …

Redis性能优化:关键配置和最佳实践

大家好&#xff0c;我是升仔 Redis作为一个高性能的键值存储系统&#xff0c;在现代应用架构中扮演着至关重要的角色。性能优化是Redis部署与维护中的一个关键环节。本文将从关键配置、持久化配置、实践场景和异常处理配置等方面&#xff0c;详细介绍如何优化Redis的性能。 关…

桶装水送水小程序:提升服务质量的利器

随着移动互联网的发展&#xff0c;越来越多的消费者通过手机在线购物和订购商品。如果你是一名桶装水供应商&#xff0c;想要拓展线上业务&#xff0c;那么开发一个桶装水微信小程序将是一个明智的选择。本文将指导你从零开始开发一个桶装水微信小程序&#xff0c;让你轻松完成…

Coze在手,GPTsDALLE免费用

1. 关于Coze Coze 是一个应用程序编辑平台&#xff0c;旨在开发下一代人工智能聊天机器人。 你可以使用无代码创建各种类型的聊天机器人&#xff0c;并将其部署到各种社交平台和消息应用程序。 链接: Coze 2. Coze的特点 Coze有5个特点。下面由我来详细介绍一下&#xff01;…

高级数据结构 <二叉搜索树>

本文已收录至《数据结构(C/C语言)》专栏&#xff01; 作者&#xff1a;ARMCSKGT 目录 前言正文二叉搜索树的概念二叉搜索树的基本功能实现二叉搜索树的基本框架插入节点删除节点查找函数中序遍历函数析构函数和销毁函数(后序遍历销毁)拷贝构造和赋值重载(前序遍历创建)其他函数…

基于多反应堆的高并发服务器【C/C++/Reactor】(下)

Listerner 有监听端口和用于监听的文件描述符。把用于监听的文件描述符或者通信的文件描述符进行了封装&#xff0c;封装好了之后对应一个通道。我如果想要接收客户端的连接&#xff0c;需要一个文件描述符。所有的客户端向我发起了连接请求&#xff0c;都需要通过这个文件描述…

蓝牙物联网与嵌入式开发如何结合?

蓝牙物联网与嵌入式开发可以紧密结合&#xff0c;以实现更高效、更智能的物联网应用。以下是一些结合的方式&#xff1a; 嵌入式开发为蓝牙设备提供硬件基础设施和控制逻辑&#xff1a;嵌入式系统可以利用微处理器和各种外设组成的系统&#xff0c;为蓝牙设备提供硬件基础设施和…

基于ERC20代币协议实现的去中心化应用平台

文章目录 内容简介设计逻辑ERC20TokenLoanPlatform 合约事件结构体状态变量函数 Remix 运行实现部署相关智能合约存款和取款贷款和还款 源码地址 内容简介 使用 solidity 实现的基于 ERC20 代币协议的借贷款去中心化应用平台(极简版)。实现存款、取款、贷款、还款以及利息计算的…