最近在項目中遇到了一個在客戶端中的webview中嵌入iframe頁面的問題,但是嵌入的iframe無法自己撐開,所以需要webview中給iframe一個高度。
這就比較尷尬了,因為webview肯定不知道iframe的高度,所以需要iframe給傳一個高度出來。
經過一番查找之后,知道了一種很方便的方法-postMessage方法。
先來看看他的語法:
otherWindow.postMessage(data, origin, [transfer]);
otherWindow
- 其他窗口的一個引用,比如iframe的contentWindow屬性、執行window.open返回的窗口對象、或者是命名過或數值索引的window.frames。這里即可以是父窗口,也可以子窗口,兩者是可以相互傳遞數據的。
data
- 將要發送到其他window的數據。它將會被結構化克隆算法序列化(這個不懂是什么意思)。這意味著你可以不受什么限制的將數據對象安全的傳送給目標窗口而無需自己序列化?;臼鞘裁磪刀伎梢?,字符串、數字、對象、數組,都OK。
origin
- 字符串參數,指明目標窗口的源,協議+主機+端口號[+URL],URL會被忽略,所以可以不寫,這個參數是為了安全考慮,postMessage()方法只會將message傳遞給指定窗口,當然如果愿意也可以建參數設置為"*",這樣可以傳遞給任意窗口,如果要指定和當前窗口同源的話設置為"/"。
transfer(可選)
- 是一串和message 同時傳遞的 Transferable 對象. 這些對象的所有權將被轉移給消息的接收方,而發送一方將不再保有所有權。(不懂是什么意思,一般沒有什么用吧,望大神指點)
父頁面獲取iframe頁面信息:
demo我放在github上的:
demo地址:父頁面獲取iframe頁面信息
父頁面:
<body>
<p>我是父頁面</p>
<p>接收到的iframe信息是:<span id="content"></span></p>
<iframe src="/btoa/b.html" frameborder="0" marginheight="0" marginwidth="0"></iframe>
<script>
// event 參數中有 data 屬性,就是iframe頁面發送過來的數據
window.addEventListener("message", function(event) {
// 把iframe頁面發送過來的數據顯示在父頁面中
document.getElementById("content").innerHTML= event.data;
}, false);
</script>
</body>
iframe頁面
<body>
<p>我是iframe頁面</p>
<div>發送的信息是:<input id="iframe" type="text"><input id="sendBtn" type="button" value="發送"></div>
<script>
// 點擊按鈕后向父頁面發送數據
document.getElementById('sendBtn').onclick = function() {
// window.parent代表父頁面
window.parent.postMessage(document.getElementById("iframe").value, '*');
}
</script>
</body>
iframe頁面獲取父頁面信息:
demo我放在github上的:
demo地址:iframe頁面獲取父頁面信息
父頁面:
<body>
<p>我是父頁面</p>
<div>發送的信息是:<input id="iframe" type="text"><input id="sendBtn" type="button" value="發送"></div>
<iframe src="/atob/b.html" frameborder="0" marginheight="0" marginwidth="0"></iframe>
<script>
// 點擊按鈕后向iframe頁面發送數據
document.getElementById('sendBtn').onclick = function() {
// window.frames[0]代表第一個iframe頁面
window.frames[0].postMessage(document.getElementById("iframe").value, '*');
}
</script>
</body>
iframe頁面
<body>
<p>我是iframe頁面</p>
<p>接收到的父頁面信息是:<span id="content"></span></p>
<script>
// event 參數中有 data 屬性,就是父頁面發送過來的數據
window.addEventListener("message", function(event) {
// 把父頁面發送過來的數據顯示在父頁面中
document.getElementById("content").innerHTML= event.data;
}, false);
</script>
</body>
通過這兩個簡單的例子我們會發現postMessage的強大之處,有了postMessage,我們甚至可以在兩個iframe之間傳送數據,只需要一個共同的父元素做中間頁。
需要注意的地方:
兼容性:
通過圖上可以看出,基本大部分的都能兼容的,但是需要注意一下這句話。
Internet Explorer 8 and 9, and Firefox versions 6.0 and below only support strings as postMessage's message.(ie 8和9,和Firefox 6.0及以下版本只支持字符串作為postMessage的消息。)
所以如果需要支持這些版本的需要注意data只能是字符串。
安全性:
在線上進行交互時,最好做好安全措施,對于postMessage,最好采用“雙向安全機制”。發送方發送數據的時候,確認接受方的源(所以最好不要用*),而接受方監聽到message事件后,也可以用event.origin判斷是否來自于正確可靠的發送方。并且最好做一下傳遞數據的數據類型校驗。如以下代碼:
function checkMessage(event) {
// 只獲取需要的域,并非所有都可以跨域
if (event.origin != "need domain") {
return false;
}
var data = event.data;
// 傳輸數據類型校驗
if (typeof(data) !== 'object') {
return false;
}
// data 的type中包含xxx則為xxx需要字段。
return data.type === "xxx";
};
并且通過不同的type可以處理不同的數據,如以下代碼:
switch (checkMessage(event)) {
case 'height':
$("#bet_"+e.data.id).css("height", (e.data.height+1) + "px");
break;
case 'jumpDown':
window.location.href = downUrl;
break;
default:
break;
}
順便貼一下本人的博客:yellowlemon的博客