利用postMessage解決webview中iframe數據交互問題

最近在項目中遇到了一個在客戶端中的webview中嵌入iframe頁面的問題,但是嵌入的iframe無法自己撐開,所以需要webview中給iframe一個高度。

webview的Bug

這就比較尷尬了,因為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之間傳送數據,只需要一個共同的父元素做中間頁。


需要注意的地方:

兼容性:

caniuse

通過圖上可以看出,基本大部分的都能兼容的,但是需要注意一下這句話。

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的博客

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,521評論 25 708
  • 1. 什么是跨域? 跨域一詞從字面意思看,就是跨域名嘛,但實際上跨域的范圍絕對不止那么狹隘。具體概念如下:只要協議...
    他在發呆閱讀 830評論 0 0
  • 1. 什么是跨域? 跨域一詞從字面意思看,就是跨域名嘛,但實際上跨域的范圍絕對不止那么狹隘。具體概念如下:只要協議...
    w_zhuan閱讀 541評論 0 0
  • 秋風瀟瀟寒霜起,欲訴衷腸,錦書難寄。漿聲杳杳雁無跡,一彎新月,數首舊詞。仔細思量未趁意,花未爽約,人誤佳期。菊瘦花...
    簡書作者木瓜閱讀 437評論 9 8
  • 這篇文章適合大部分像我這種需要做PPT、有點基礎而且懶不想加班的職場人,以及需要自己做圖片的苦逼新媒體工作從業者。...
    肉肉_Jade閱讀 482評論 0 9