JS實(shí)現(xiàn)兩個(gè)跨域頁面實(shí)現(xiàn)量子糾纏互動效果
本文約定:
A頁面:假設(shè)為a.com
B頁面:假設(shè)為b.com
一、同域頁面實(shí)現(xiàn)量子糾纏的一般方案
最近前端圈的量子糾纏交互動效爆火,相信大家都了解了其中的實(shí)現(xiàn)原理,這里我再簡單的介紹下,不了解的同學(xué)的可以學(xué)習(xí)一波。
原理就是,通過監(jiān)聽窗口的位置、大小等信息,然后實(shí)時(shí)地保存到localStorage中,另一個(gè)頁面通過監(jiān)聽strorage的改變,進(jìn)而動態(tài)地改變頁面上物體的位置和顯示效果。
示例代碼如下:
// 將當(dāng)前頁面的中心位置坐標(biāo)保存到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被修改后的回調(diào) 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);
在這個(gè)案例中,由于兩個(gè)頁面是相同域下的,所以另外一個(gè)頁面可以通過監(jiān)聽strorage的改變,獲取到前一個(gè)頁面保存進(jìn)去的值,然后進(jìn)行交互,這里不得不佩服作者的奇思妙想。
那么問題來了,如果兩個(gè)頁面是跨域的,單獨(dú)打開的兩個(gè)頁面又如何進(jìn)行實(shí)時(shí)地通信呢?有同學(xué)會說用WebSocket,呃...,是可以實(shí)現(xiàn),但我們討論的是純前端的實(shí)現(xiàn),借助后端就沒啥意思了。
二、跨域頁面實(shí)現(xiàn)量子糾纏的終極方案
兩個(gè)跨域頁面想要通信就必須使用可以進(jìn)行跨域通信的API,大家肯定都想到了,對,使用window.postMessage,但是A頁面要給B頁面發(fā)送消息,那么postMessage的window對象就必須是B頁面的window對象,而A和B兩個(gè)頁面是在兩個(gè)單獨(dú)的瀏覽器窗口中分別打開的,A頁面如何獲取到B頁面的window對象呢?
直接說結(jié)論,終極方案就是,在A頁面中通過Iframe嵌入display為none的B頁面,A頁面監(jiān)聽窗口的位置、大小的改變,然后將窗口信息通過postMessage發(fā)送消息給B頁面,剛才說了要給B頁面發(fā)送消息就必須拿到B頁面的window對象,那么如何拿到呢,就是通過Iframe.contentWindow,B頁面通過監(jiān)聽A頁面發(fā)送的message拿到信息,然后保存到window.localStorage中。這里有同學(xué)會好奇了,既然B頁面拿到了信息,為啥還要保存到localStorage中,為啥不直接使用呢?你聽我狡辯...,啊不,你聽我說,這里拿到信息的B頁面只是A頁面中嵌入的B頁面,不是用戶打開的另一個(gè)窗口中的B頁面,所以這時(shí)剩下的工作就是將嵌入的B頁面中的信息發(fā)送給另一個(gè)窗口的B頁面,就大功告成了。兩個(gè)都是B頁面,就不存在跨域啦,就使用上面那個(gè)方案,通過監(jiān)聽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);
三、實(shí)戰(zhàn)案例
Visualization Collection網(wǎng)站中已經(jīng)實(shí)現(xiàn)了量子糾纏的效果,大家可以去玩一玩,該網(wǎng)站中的量子糾纏效果作為隱藏款案例,點(diǎn)擊網(wǎng)站左上角頭部的文字,即可觸發(fā),一般我不說的。
體驗(yàn)地址(PC端):hepengwei.cn
源碼地址:github.com/hepengwei/visualization-collection
四、美中不足
大家也看到了,上面GIF圖中演示的還是同域頁面實(shí)現(xiàn)量子糾纏的效果,這里非常遺憾地告訴大家,跨域頁面實(shí)現(xiàn)量子糾纏只能在本地運(yùn)行的情況下才可實(shí)現(xiàn),部署到線上就不行了,監(jiān)聽storage的回調(diào)不會執(zhí)行,后面我也試過各種辦法,比如在定時(shí)器里循環(huán)去獲取localStorage中的值,使用Service Worker等均無法實(shí)現(xiàn),這應(yīng)該是瀏覽器為了安全考慮進(jìn)行了限制。
如果有想要看兩個(gè)跨域頁面在本地實(shí)現(xiàn)量子糾纏效果的同學(xué),可以自行到我GitHub上下載visualization-collection和michelle-design這兩個(gè)項(xiàng)目代碼,然后在本地運(yùn)行,就可以看到效果啦。
五、結(jié)語
該終極方案與我的另一篇文章《兩個(gè)跨越頁面進(jìn)行跳轉(zhuǎn)傳參的終極方案》中的終極方案有異曲同工之妙,都是通過在原先的頁面中無痕嵌入另一個(gè)頁面,然后通過myIframe.contentWindow.postMessage來發(fā)送消息,如此實(shí)現(xiàn)跨域信息的傳遞。兩個(gè)不同窗口打開的同域頁面,則通過將信息保存到localStorage,另一頁面通過監(jiān)聽storage改變的方式傳遞信息。
到此這篇關(guān)于JS實(shí)現(xiàn)兩個(gè)跨域頁面實(shí)現(xiàn)量子糾纏互動效果的文章就介紹到這了,更多相關(guān)JS跨域頁面互動內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
利用Vconsole和Fillder進(jìn)行移動端抓包調(diào)試方法
這篇文章主要介紹了利用Vconsole和Fillder進(jìn)行移動端抓包調(diào)試,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-03-03JavaScript數(shù)據(jù)結(jié)構(gòu)與算法之隊(duì)列原理與用法實(shí)例詳解
這篇文章主要介紹了JavaScript數(shù)據(jù)結(jié)構(gòu)與算法之隊(duì)列原理與用法,較為詳細(xì)的說明了隊(duì)列的概念、原理,并結(jié)合實(shí)例形式分析了javascript實(shí)現(xiàn)與使用隊(duì)列的相關(guān)操作技巧與注意事項(xiàng),需要的朋友可以參考下2017-11-11JavaScript利用正則表達(dá)式替換字符串中的內(nèi)容
本文主要介紹了JavaScript利用正則表達(dá)式替換字符串中內(nèi)容的具體實(shí)現(xiàn)方法,并做了簡要注釋,便于理解。具有一定的參考價(jià)值,需要的朋友可以看下2016-12-12javascript的解析執(zhí)行順序在各個(gè)瀏覽器中的不同
javascript是一種解釋型語言,它的執(zhí)行是自上而下的。由于各個(gè)瀏覽器對它的理解有所差異,所以我們有必要深入理解js的執(zhí)行順序2014-03-03JS實(shí)現(xiàn)在線統(tǒng)計(jì)一個(gè)頁面內(nèi)鼠標(biāo)點(diǎn)擊次數(shù)的方法
這篇文章主要介紹了JS實(shí)現(xiàn)在線統(tǒng)計(jì)一個(gè)頁面內(nèi)鼠標(biāo)點(diǎn)擊次數(shù)的方法,實(shí)例分析了javascript操作Cookie實(shí)現(xiàn)計(jì)數(shù)的技巧,需要的朋友可以參考下2015-02-02僅IE9/10同時(shí)支持script元素的onload和onreadystatechange事件分析
測試結(jié)果可以看出,IE9后已經(jīng)開始支持script的onload事件了。一直以來我們判斷js文件是否已經(jīng)加載完成就是用以上的兩個(gè)事件。2011-04-04