前端缓存无论locastorage、sessionstorage、indexedDB,都只能在本域进行数据共享,如果要跨页面进行信息传输,那就得另辟蹊径。
- 思路1:在url上加参数
这种方式最简便,但是url长度是有限制的,数据太多就不得行了; - 思路2:写个接口传输
这种方式太笨重,肯定不考虑啊 - 思路3:用
window.postMessage
got it!window.postMessage
方法可以安全地实现跨源通信。
先来模拟一下需求:有两个项目A和B,产品经理希望:
- 在A点个按钮可以打开B
- A要把大量的数据传给B,让B一进入页面就能用数据进行业务操作
- B接收了信息要回复A已确认收到
假设项目A端口是3001,项目B端口是3002
项目A代码如下:
<script setup>
import { ref } from "vue";
const bReply = ref("");
const gotoB = () => {
const targetPage = window.open("http://127.0.0.1:3002/", "/"); // 解决需求1
targetPage.postMessage(
{ msg: { ··· /* 这里是很大的数据量*/ } },
"http://127.0.0.1:3002"
); // 解决需求2,发送信息
};
// 解决需求3,监听回复消息
const receiveMessage = (event) => {
if (event.data) {
bReply.value = event.data;
}
};
window.addEventListener("message", receiveMessage, false);
</script>
<template>
<h1>项目A</h1>
<button type="button" @click="gotoB">打开跨域项目B</button>
<div>项目B回复:{{ bReply }}</div>
</template>
项目B代码如下:
<script setup>
import { ref, onMounted } from "vue";
let msg = ref("");
const receiveMessage = (event) => {
msg.value = event.data.msg;
event.source.postMessage("我已收到", event.origin); // 解决需求3,回复消息
};
window.addEventListener("message", receiveMessage, false); // 解决需求2,接收信息
</script>
<template>
<h1>项目B</h1>
<div>项目A传来的数据:{{ JSON.stringify(msg) }}</div>
</template>
</style>
以上代码就能实现跨域页面传输信息了,但是还存在两个问题:
- 如果没有限制接收消息源,接收方可以收到所有发送方的信息,这样会有安全问题,所以要限制消息源。
在receiveMessage
方法里增加event.origin
判断,A和B的receiveMessage
都要添加。
const receiveMessage = (event) => {
if (event.origin !== "http://127.0.0.1:3000") return; // ⚠️添加限制
msg.value = event.data.msg;
event.source.postMessage("我已收到", event.origin); // 解决需求3,回复消息
};
- 以上代码跑起来会发现项目B有一定概率接收不到数据,这是因为异步执行的原因,所以应该在发送方法中添加延迟
const gotoB = () => {
const targetPage = window.open("http://127.0.0.1:3002/", "/");
setTimeout(() => {
targetPage.postMessage(
{ msg: { ··· /* 这里是很大的数据量*/ } },
"http://127.0.0.1:3002"
);
}, 1000);
};
last but not least,postMessage的浏览器兼容性很好