はじめに
iframe表示部分のクリックイベントを取得するという記事で、iframe内のイベントをiframeのcontentWindowに対しaddEventlistenerを登録して親ページで取得する方法を紹介しました。
この記事ではpostMessageを利用してiframeと親ページ間でやり取りする方法を紹介します。
この記事の対象者
- ページに埋め込んだiframe要素から情報を取得したい
- ページに埋め込んだiframe要素と親ページ間で相互間のデータ送受信を行いたい
- ページにiframe埋め込みをする前提のページを作成して、イベント発生時に親ページに情報を渡したい
iframeと親ページ間のデータ送受信
postMessageを利用した送受信の方法
子ページ
データを親ページに送信する場合
window.parent.postMessage(message, targetOrigin);
// 例
window.parent.postMessage("sample.jpでしか受信出来ないメッセージです", "https://sample.jp");
window.parent.postMessage({
type: "sample",
data: {
message: "誰でも受信できるメッセージです",
},
}, "*");
const example = {
type: "example",
data: {
message: "JSONで渡すメッセージです",
}
}
window.parent.postMessage(JSON.stringfy(example), "*");
引数の説明
- message
他のウィンドウに送られるデータです。
決められた型は無いですが、オブジェクトで渡すことでtypeやdataなど親ページで扱いやすい内容で渡すことが出来ます。
- targetOrigin
データを送信した際の受け取り側のオリジンを限定することが出来ます。
例えばhttps://sample.jp
とした場合は、オリジンがhttps://sample.jp
のウィンドウでしかデータは受信出来ません。
postMessageの送信先が決まっている場合はオリジン指定をしましょう。
データを親ページから受信する場合
window.addEventListener("message", (response) => {
// 取得した内容を利用した処理
})
postMessageで送信されたデータを受け取るには、addEventListenerで登録したmessageイベントを検知することで取得することが出来ます。
親ページ
データをiframeで埋め込んだ子ページに送信する場合
const iframeElement = document.querySelector("iframe");
iframeElement.contentWindow.postMessage(message, targetOrigin);
iframeのWindowオブジェクトにアクセスして、先ほどと同じようにpostMessageを実行しています。
データを子ページから受信する場合
window.addEventListener("message", (response) => {
// 取得した内容を利用した処理
})
こちらは子ページで受信する場合と違いありません。
以上がiframeと親ページ間でpostMessageを利用してデータ送受信を行う方法になります。
使用例
以下postMessageの使用例です。iframeと親ページで連携して相互間のデータ受け渡しをする例を紹介します。
iframeでボタンクリックされた回数を親ページに渡す
iframe
let leftCount = 0;
const leftClick = () => {
const message = {
type: "click",
data: {
name: "left",
count: leftCount,
}
}
window.parent.postMessage(message, "*");
leftCount++;
}
let rightCount = 0;
const rightClick = () => {
const message = {
type: "click",
data: {
name: "right",
count: rightCount,
}
}
window.parent.postMessage(message, "*");
rightCount++;
}
// オリジンが異なるので親ページでは受信出来ない
const originRestricted = () => {
const message = {
type: "click",
data: {
name: "restricted",
}
}
window.parent.postMessage(message, "https://sample.jp");
}
親ページ
window.addEventListener("message", (response) => {
if (response.data.type === "click") {
const data = response.data.data;
if (data.name === "left") {
const leftNumberElement = document.querySelector("#left-number");
leftNumberElement.innerHTML = data.count;
} else if (data.name === "right") {
const rightNumberElement = document.querySelector("#right-number");
rightNumberElement.innerHTML = data.count;
}
}
})
親ページで選択された色をiframeで表示する
親ページ
const postColor = (color) => {
const iframeElement = document.querySelector("iframe");
const message = {
type: "color",
data: {
color: color,
}
}
iframeElement.contentWindow.postMessage(message, "*");
}
iframe
window.addEventListener("message", (response) => {
if (response.data.type === "color") {
const messageAreaElement = document.querySelector(".message-area");
const createDivElement = document.createElement("div");
const color = response.data.data.color;
if (color === "red") {
createDivElement.className = "red";
} else if (color === "blue") {
createDivElement.className = "blue";
} else if (color === "yellow") {
createDivElement.className = "yellow";
}
messageAreaElement.appendChild(createDivElement);
}
})