これは、シグナルの送信時に子 iframe がロードされていないため、iframe.src に適切な値が設定されていないことが原因である可能性があります。
いくつかのテストを行ったところ、あなたと同じエラーが発生しましたが、postMessage 呼び出しを setTimeout でラップして 100 ミリ秒待機すると、エラーは発生しませんでした。これは、これが初期化の競合状態であることを示しています。
setTimeout なしでよりクリーンなソリューションを実装する方法は次のとおりです。
親:
window.addEventListener("DOMContentLoaded", function() {
var iframe = document.querySelector("iframe")
, _window = iframe.contentWindow
window.addEventListener("message", function(e) {
// wait for child to signal that it's loaded.
if ( e.data === "loaded" && e.origin === iframe.src.split("/").splice(0, 3).join("/")) {
// send the child a message.
_window.postMessage("Test", iframe.src)
}
})
}, false)
子:
window.addEventListener("DOMContentLoaded", function() {
// signal the parent that we're loaded.
window.parent.postMessage("loaded", "*")
// listen for messages from the parent.
window.addEventListener("message", function(e) {
var message = document.createElement("h1")
message.innerHTML = e.data
document.body.appendChild(message)
}, false)
}, false)
これは、子が読み込まれたことを誰かに通知する簡単な解決策です (「*」を使用します。機密情報は何も送信されていないため、これで問題ありません)。親は、読み込まれたイベントをリッスンし、関心のある子であることを確認します。その中でそれを放出しています。
次に、親は子にメッセージを送信し、子はそれを受信する準備ができています。子はメッセージを受け取ると、データを <h1> に入れ、それを <body> に追加します。
実際のサブドメインを使用して Chrome でこれをテストしたところ、このソリューションが機能しました。