vue中iframe使用以及結(jié)合postMessage實(shí)現(xiàn)跨域通信
使用場(chǎng)景
需求
在一個(gè)H5項(xiàng)目的頁(yè)面中以u(píng)rl的方式嵌入另一個(gè)項(xiàng)目的頁(yè)面。(不得不使用iframe)
而為了兼容移動(dòng)端api(封裝的一個(gè)移動(dòng)端api,iframe內(nèi)嵌頁(yè)面不生效),需要實(shí)現(xiàn)父子頁(yè)面的通信 (使用postMessage)。
iframe使用
基本使用
直接在頁(yè)面嵌套iframe標(biāo)簽指定src即可使用iframe。
<iframe src="xxx.html"></iframe>
常用屬性
frameborder
:是否顯示邊框,1(yes),0(no)height
:框架作為一個(gè)普通元素的高度。width
:框架作為一個(gè)普通元素的寬度。name
:框架的名稱(chēng),window.frames[name]時(shí)專(zhuān)用的屬性。scrolling
:框架的是否滾動(dòng)。yes,no,auto。src
:內(nèi)框架的地址,可以使頁(yè)面地址,也可以是圖片的地址。sandbox
:對(duì)iframe進(jìn)行一些列限制,IE10+支持
更多屬性訪問(wèn): 這里
iframe高度自適應(yīng)
let ifr = document.getElementById('ifr') const deviceHeight = document.documentElement.clientHeight; ifr.style.height = (Number(deviceHeight)) + 'px';?
vue中需要在mounted()中進(jìn)行高度初始化
獲取iframe的內(nèi)容
通過(guò)兩個(gè)主要的API:contentWindow 和 contentDocument
iframe.contentWindow
,獲取iframe的window對(duì)象iframe.contentDocument
,獲取iframe的document對(duì)象
var iframe = document.getElementById("iframe1"); var iwindow = iframe.contentWindow; var idoc = iwindow.document; console.log("window",iwindow);?? ?//獲取iframe的window對(duì)象 console.log("document",idoc);?? ?//獲取iframe的document console.log("html",idoc.documentElement);?? ?//獲取iframe的html console.log("head",idoc.head);?? ?//獲取head console.log("body",idoc.body);?? ?//獲取body
通過(guò)Name屬性,通過(guò)window提供的frames獲取
<iframe src ="xxx.html" id="ifr1" name="ifr1" scrolling="yes"> ? ? <p>Your browser does not support iframes.</p> </iframe> <script type="text/javascript"> ? ? console.log(window.frames['ifr1'].window); ? ? console.dir(document.getElementById("ifr1").contentWindow); </script>
window.frames['ifr1'] 返回的就是window對(duì)象,即 window.frames['ifr1']===window
同域下獲取父級(jí)/子級(jí)內(nèi)容
window.parent
:獲取上一級(jí)的window對(duì)象,如果還是iframe則是該iframe的window對(duì)象window.top
:獲取最頂級(jí)容器的window對(duì)象
iframe跨域
以下形式的跨域,可以使用iframe進(jìn)行解決。某一方使用iframe嵌套在另一方。
比如:http://www.foo.com/a.html 和 http://script.foo.com/b.html
兩個(gè)文件中分別加上 document.domain = 'foo.com',指定相同的主域,然后,兩個(gè)文檔就可以進(jìn)行交互。
//b.html是以iframe的形式嵌套在a.html中 //www.foo.com上的a.html document.domain = 'foo.com'; var ifr = document.createElement('iframe'); ifr.src = 'http://script.foo.com/b.html'; ifr.style.display = 'none'; document.body.appendChild(ifr); ifr.onload = function(){ ? ? var doc = ifr.contentDocument || ifr.contentWindow.document; ? ? // 在這里操縱b.html ? ? alert(doc.getElementsByTagName("h1")[0].childNodes[0].nodeValue); }; //script.foo.com上的b.html document.domain = 'foo.com';
默認(rèn)情況下 document.domain 是指 window.location.hostname ??梢允謩?dòng)更改,但是最多只能設(shè)置為主域名。 通常,主域名就是指不帶www的hostname, 比如: foo.com , baidu.com 。
如果,帶上www或者其他的前綴,就是二級(jí)域名或者多級(jí)域名。通過(guò)上述設(shè)置,相同的domain之后,就可以進(jìn)行同域的相關(guān)操作。
如果設(shè)置的iframe的域名和 top.window 的域名完全不同。則可以使用postMessage()進(jìn)行通信
postMessage通信
window.postMessage() 方法可以安全地實(shí)現(xiàn)跨源通信。通常,對(duì)于兩個(gè)不同頁(yè)面的腳本,只有當(dāng)執(zhí)行它們的頁(yè)面位于具有相同的協(xié)議(通常為https),端口號(hào)(443為https的默認(rèn)值),以及主機(jī) (兩個(gè)頁(yè)面的模數(shù) Document.domain設(shè)置為相同的值) 時(shí),這兩個(gè)腳本才能相互通信。window.postMessage() 方法提供了一種受控機(jī)制來(lái)規(guī)避此限制,只要正確的使用,這種方法就很安全。
具體使用方式參考:window.postMessage
<iframe src="http://xxx.com" name="sendMessage"></iframe>
父頁(yè)面向子頁(yè)面?zhèn)鬟f信息:
// 父頁(yè)面js let ifr = window.frames['sendMessage']; // 向子頁(yè)面發(fā)送message ifr.postmessage('give u a message', "http://xxx.com"); // xxx.com頁(yè)面js // 監(jiān)聽(tīng)父頁(yè)面?zhèn)鱽?lái)的信息 window.addEventListener('message', receiver, false); function receiver(e) { ? ? if (e.origin == 'http://xxx.com') { ? ? ? ? if (e.data == 'give u a message') { ? ? ? ? ? ? e.source.postMessage('received', e.origin); ?// 向原網(wǎng)頁(yè)返回信息 ? ? ? ? } else { ? ? ? ? ? ? alert(e.data); ? ? ? ? } ? ? } }
在vue中使用
<iframe :src="src" ref="iframe" frameborder="0"></iframe>
1.要將獲取到iframe的contentWindow屬性放到mounted這個(gè)鉤子函數(shù)中。
mounted() { ? ? this.iframeWin = this.$refs.iframe.contentWindow; }
2.子頁(yè)面向父頁(yè)面?zhèn)髦?/p>
父頁(yè)面代碼:
// 父頁(yè)面監(jiān)聽(tīng)子頁(yè)面?zhèn)鱽?lái)的信息 mounted() { ? ? window.addEventListener('message', this.handleMessage); ? ? this.iframeWin = this.$refs.iframe.contentWindow; }, methods: { ? ? handleMessage (event) { ? ? ? ? const data = event.data.data ? ? ? ? if(data.info === "success"){ ? ? ? ? ? ? alert(data.data) ? ? ? ? } ? ? } }
子頁(yè)面代碼:
sendMessage() { ? ? // 向父頁(yè)面發(fā)送信息 ? ? window.parent.postMessage({ ? ? ? ? data: { ? ? ? ? ? ? info:"success", ? ? ? ? ? ? data:"我是子頁(yè)面的test!" ? ? ? ? } ? ? }, '*'); }
3.父頁(yè)面向子頁(yè)面?zhèn)鬟f信息同理
sendMessage () { ? ? // 向子頁(yè)面?zhèn)鲾?shù)據(jù),需要注意這里沒(méi)有parent ? ? this.iframeWin.postMessage({ ? ? ? ? info: 'success', ? ? ? ? data: "我是來(lái)自父頁(yè)面的data!" ? ? }, '*') }
注意父向子傳遞信息的時(shí)候,要等子頁(yè)面加載完成后,再進(jìn)行通信
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
vue3中reactive和ref的實(shí)現(xiàn)與區(qū)別詳解
reactive和ref都是vue3實(shí)現(xiàn)響應(yīng)式系統(tǒng)的api,他們是如何實(shí)現(xiàn)響應(yīng)式的呢,reactive和ref又有什么區(qū)別呢,下面小編就來(lái)和大家詳細(xì)講講,希望對(duì)大家有所幫助2023-10-10vue項(xiàng)目實(shí)現(xiàn)添加圖片裁剪組件
這篇文章主要為大家詳細(xì)介紹了vue項(xiàng)目實(shí)現(xiàn)添加圖片裁剪組件,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03解決vue路由發(fā)生了跳轉(zhuǎn)但是界面沒(méi)有任何反應(yīng)問(wèn)題
這篇文章主要介紹了解決vue路由發(fā)生了跳轉(zhuǎn)但是界面沒(méi)有任何反應(yīng)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04vue項(xiàng)目npm?run?build打包dist文件及打包后空白解決辦法
npm run build 這個(gè)命令會(huì)執(zhí)行Vue CLI中預(yù)定義的打包配置,并將打包后的文件存放在"dist"文件夾中,這篇文章主要給大家介紹了關(guān)于vue項(xiàng)目npm?run?build打包dist文件及打包后空白的解決辦法,需要的朋友可以參考下2023-10-10