JS实现两个跨域页面实现量子纠缠互动效果
作者:River_何
本文约定:
A页面:假设为a.com
B页面:假设为b.com
一、同域页面实现量子纠缠的一般方案
最近前端圈的量子纠缠交互动效爆火,相信大家都了解了其中的实现原理,这里我再简单的介绍下,不了解的同学的可以学习一波。
原理就是,通过监听窗口的位置、大小等信息,然后实时地保存到localStorage中,另一个页面通过监听strorage的改变,进而动态地改变页面上物体的位置和显示效果。
示例代码如下:
// 将当前页面的中心位置坐标保存到localStorage中 const savePageInfo = () => { const centerX = window.innerWidth / 2 + window.screenLeft; const centerY = window.innerHeight / 2 + window.screenTop; const data = { centerX, centerY }; window.localStorage.setItem(pageId, JSON.stringify(data)); }; // localStorage被修改后的回调 const onStorage = (e) => { console.log("otherPageInfo", JSON.parse(e.newValue)); } const onReady = () => { savePageInfo(); window.addEventListener("resize", savePageInfo); window.addEventListener("storage", onStorage); } window.addEventListener("ready", onReady);
在这个案例中,由于两个页面是相同域下的,所以另外一个页面可以通过监听strorage的改变,获取到前一个页面保存进去的值,然后进行交互,这里不得不佩服作者的奇思妙想。
那么问题来了,如果两个页面是跨域的,单独打开的两个页面又如何进行实时地通信呢?有同学会说用WebSocket,呃...,是可以实现,但我们讨论的是纯前端的实现,借助后端就没啥意思了。
二、跨域页面实现量子纠缠的终极方案
两个跨域页面想要通信就必须使用可以进行跨域通信的API,大家肯定都想到了,对,使用window.postMessage,但是A页面要给B页面发送消息,那么postMessage的window对象就必须是B页面的window对象,而A和B两个页面是在两个单独的浏览器窗口中分别打开的,A页面如何获取到B页面的window对象呢?
直接说结论,终极方案就是,在A页面中通过Iframe嵌入display为none的B页面,A页面监听窗口的位置、大小的改变,然后将窗口信息通过postMessage发送消息给B页面,刚才说了要给B页面发送消息就必须拿到B页面的window对象,那么如何拿到呢,就是通过Iframe.contentWindow,B页面通过监听A页面发送的message拿到信息,然后保存到window.localStorage中。这里有同学会好奇了,既然B页面拿到了信息,为啥还要保存到localStorage中,为啥不直接使用呢?你听我狡辩...,啊不,你听我说,这里拿到信息的B页面只是A页面中嵌入的B页面,不是用户打开的另一个窗口中的B页面,所以这时剩下的工作就是将嵌入的B页面中的信息发送给另一个窗口的B页面,就大功告成了。两个都是B页面,就不存在跨域啦,就使用上面那个方案,通过监听strorage的改变获取就行了。
示例代码如下:
A页面
const postInfo = () => { const bIframe = document.getElementById("bIframe"); if (bIframe) { const centerX = window.innerWidth / 2 + window.screenLeft; const centerY = window.innerHeight / 2 + window.screenTop; const data = { centerX, centerY }; bIframe.contentWindow?.postMessage( JSON.stringify(data), "http://b.com" ); } }; const onMessage = (e) => { if (e.origin !== "http://b.com") return; if (e.data) { window.localStorage.setItem("bPageInfo", e.data); } }; const onStorage = (e) => { if (e.key === "bPageInfo") { console.log("bPageInfo", JSON.parse(e.newValue)); } }; const onReady = () => { window.addEventListener("message", onMessage, false); if (window.self === window.top) { window.addEventListener("storage", onStorage); window.addEventListener("resize", postInfo); } postInfo(); } window.addEventListener("ready", onReady);
在A页面中嵌入B页面
<iframe id="bIframe" src="http://b.com" style="display: none" />
B页面
const postInfo = () => { const aIframe = document.getElementById("aIframe"); if (aIframe) { const centerX = window.innerWidth / 2 + window.screenLeft; const centerY = window.innerHeight / 2 + window.screenTop; const data = { centerX, centerY }; aIframe.contentWindow?.postMessage( JSON.stringify(data), "http://a.com" ); } }; const onMessage = (e) => { if (e.origin !== "http://a.com") return; if (e.data) { window.localStorage.setItem("aPageInfo", e.data); } }; const onStorage = (e) => { if (e.key === "aPageInfo") { console.log("aPageInfo", JSON.parse(e.newValue)); } }; const onReady = () => { window.addEventListener("message", onMessage, false); if (window.self === window.top) { window.addEventListener("storage", onStorage); window.addEventListener("resize", postInfo); } postInfo(); } window.addEventListener("ready", onReady);
三、实战案例
Visualization Collection网站中已经实现了量子纠缠的效果,大家可以去玩一玩,该网站中的量子纠缠效果作为隐藏款案例,点击网站左上角头部的文字,即可触发,一般我不说的。
体验地址(PC端):hepengwei.cn
源码地址:github.com/hepengwei/visualization-collection
四、美中不足
大家也看到了,上面GIF图中演示的还是同域页面实现量子纠缠的效果,这里非常遗憾地告诉大家,跨域页面实现量子纠缠只能在本地运行的情况下才可实现,部署到线上就不行了,监听storage的回调不会执行,后面我也试过各种办法,比如在定时器里循环去获取localStorage中的值,使用Service Worker等均无法实现,这应该是浏览器为了安全考虑进行了限制。
如果有想要看两个跨域页面在本地实现量子纠缠效果的同学,可以自行到我GitHub上下载visualization-collection和michelle-design这两个项目代码,然后在本地运行,就可以看到效果啦。
五、结语
该终极方案与我的另一篇文章《两个跨越页面进行跳转传参的终极方案》中的终极方案有异曲同工之妙,都是通过在原先的页面中无痕嵌入另一个页面,然后通过myIframe.contentWindow.postMessage来发送消息,如此实现跨域信息的传递。两个不同窗口打开的同域页面,则通过将信息保存到localStorage,另一页面通过监听storage改变的方式传递信息。
到此这篇关于JS实现两个跨域页面实现量子纠缠互动效果的文章就介绍到这了,更多相关JS跨域页面互动内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!