運用 postMessage 解決 iframe 與父層溝通的問題

问题描述

当在iframe的父级监听iframe中的内容时候,如果内嵌的路由与父级的源不一致,会出现跨域问题。出现如下报错信息:

1
2
3
4
5
const iframe = document.querySelector("iframe");
iframe.onload = () => {
const iframeInner = iframe.contentWindow;
console.log(iframeInner);
};
1
2
Uncaught DOMException: Failed to read a named property 'document' from 'Window': Blocked a frame with origin "http://localhost:1024" from accessing a cross-origin frame.
at eval (

基於同源政策,如果透過 iframe 去引入不同源的頁面,我們是不能透過 JavaScript 去存取其中的任何東西的。

postMessage

如果 iframe 的 src 為不同源(http 和 https、不同的 Port、不同的 Domain),彼此之間就可以使用 window.postMessage 來溝通。

假設我現在有一個 Port 為 5501 的 parent.html 及 Port 為 5500 的 iframe.html,我們可以在 iframe.html 中輸入:

1
parent.postMessage("some message", "http://127.0.0.1:5501/parent.html");

在 parent.html 中輸入:

1
2
3
window.addEventListener("message", (e) => {
console.log(e.data);
});

應該可以在 parent.html 中看見 iframe.html 傳入的 ‘some message’ 字串。

问题回顾

最开始的问题,在 iframe 中监听 iframe 内容高度,然后通过 postMessage 传递给父级页面,父级页面监听 postMessage 事件,获取到
iframe 内容高度,再设置 iframe 高度。即可

1
2
3
4
5
// 定时发送窗口高度到父窗口
setInterval(() => {
const scrollHeight = window.document.body.scrollHeight
window.parent.postMessage(scrollHeight, '*')
}, 1000)
1
2
3
4
// 监听窗口高度自动适配
window.addEventListener("message", (e) => {
document.getElementById("reportIframe").style.height = e.data + "px"
}, false)