postMessage真香

一、什麼是postMessage

postMessage是HTML5中新引入的API,它能夠實現跨窗口以及跨域的通訊。postMessage相似與Ajax可是它不受同源策略的限制而且通訊雙方都是客戶端。javascript

二、postMessage相關API介紹

2.一、發送數據

語法:html

quoteWindow.postmessage(data, origin, [transfer])
複製代碼

quoteWindow

其中quoteWindow表示其餘窗口的一個引用,是被髮送數據的一方(接收數據),能夠是如下類型java

  1. iframe的contentWindow
<body>
    <iframe class="childIframe" scr="http://XXX:8080"></iframe>
    <script> // 獲取iframe的contentWindow const win = document.querySelector('.childIframe').contentWindow </script>
</body>
複製代碼
  1. 執行window.open()方法返回的對象
<body>
    <script> // 獲取window.open()打開窗口的引用 const win = window.open('http://XXX:8888') </script>
</body>
複製代碼
  1. 命名過或數值索引的window.frames
<body>
    <script> const iframes = window.frames </script>
</body>
複製代碼

data

data表示發送的數據,在MDN中說到:data表示將要發送到其餘 window的數據。它將會被結構化克隆算法序列化。這意味着你能夠不受什麼限制的將數據對象安全的傳送給目標窗口而無需本身序列化。[1]算法

origin

經過origin能夠指定哪些窗口能夠接收到該消息事件,它的值能夠是如下:跨域

  • "*"

表示不受限制安全

  • URL地址

表示只有該URL地址的窗口才能接收到消息。這個設計尤其重要,由於咱們在傳輸一些敏感信息的時候就須要指定窗口才能接收該事件,防止惡意攻擊。app

transfer

是一串和message 同時傳遞的Transferable對象.這些對象的全部權將被轉移給消息的接收方,而發送一方將再也不保有全部權。dom

總結一下函數

發送數據使用postMessage方法,要那個窗口發送數據就調用該窗口的postMessage的方法,並在方法中傳入相關的參數。post

2.二、接收數據

語法

window.addEventListener('message', (e) => {
    // ...
})
複製代碼

在須要接收消息的頁面中監聽一個**message**事件,當其餘窗口發送數據後就會觸發該事件,而後執行相應的事件函數。

在接收到的事件對象中有三個重要的屬性

  1. origin;表示發送消息窗口的源,能夠經過此屬性判斷源是否安全
  2. data;表示發送消息窗口發送的數據
  3. source;表示對發送消息窗口的引用,能夠用此來向發送消息的窗口返回數據

三、具體使用

定義父窗口:

<body>
  <h1>This is parent window</h1>
  <input type="text" class="inp">
  <button class="send">發送信息到iframe</button>
  <div class="contents">
    <p>接收到的信息</p>
    <ul class="messages">

    </ul>
  </div>
  <iframe src="child.html" frameborder="3" class="child-iframe" height="600" width="800"></iframe>
  <script> // 父頁面監聽message事件,接受iframe發送的消息 window.addEventListener('message', e => { if (e.origin !== 'http://127.0.0.1:5500') { // 驗證對方的身份 return } const box = document.querySelector('.messages') box.innerHTML += `<li> 收到新的信息:${e.data}, 來自於${e.origin}</li>`; }); // iframe的引用 const win = document.querySelector('.child-iframe').contentWindow document.querySelector('.send').addEventListener('click', () => { const msg = document.querySelector('.inp').value win.postMessage(msg, '*') // 這裏使用*,也能夠是iframe的URL地址 document.querySelector('.inp').value = '' }) </script>
</body>
複製代碼

定義子窗口

<body>
  <h1>This is iframe child page</h1>
  <input type="text" class="inp">
  <button class="send">發送信息到夫窗口</button>
  <div class="contents">
    <p>接收到的信息</p>
    <ul class="messages">

    </ul>
  </div>
  <script> let parentWin // 監聽父頁面的消息 window.addEventListener('message', e => { if (e.origin !== 'http://127.0.0.1:5500') { // 驗證對方的身份 return } // 發送詳細窗口的window對象引用,調用對象postMessage方法實現父子頁面的通訊,固然也可使用window.parent來通訊 parentWin = e.source const box = document.querySelector('.messages') box.innerHTML += `<li>接收到新的信息:${e.data}, 來自於${e.origin}</li>` }) console.log(window.parent.location) document.querySelector('.send').addEventListener('click', () => { const msg = document.querySelector('.inp').value window.parent.postMessage(msg, '*') //  document.querySelector('.inp').value = '' }) </script>
</body>
複製代碼

這樣就實現了父子窗口之間的通訊。以下圖:

postMessage還能夠實現跨域通訊等,後續繼續研究。

四、修改iframe中DOM節點的樣式

4.一、獲取到元素後修改

window.onload = function () {
    let dom = document.getElementById('frame').contentWindow.document.getElementById('selector')
    // 修改style
    dom.style.color = "red"
    // 修改class
    dom.classList.add('box')
}
複製代碼

4.二、在iframe的header中添加CSS樣式

若是一個元素是動態添加的就獲取不到該DOM因此能夠經過添加CSS樣式的方法。

let header = document.getElementById('frame').contentWindow.document.getElementById('header')
const CSS_STR = ` .box { color: red } `
const style = document.createElement('style')
style.innerText = CSS_STR
header.appendChild(style)
複製代碼

五、兼容性

更多文章

相關文章
相關標籤/搜索