はじめに

親 Window で iframe から送られてきたデータを受信したり、iframe 内のイベントを検出する方法。

※イベント検出もデータ送受信機能で実現しているので、厳密にはイベント検出(addEventListener 相当)ではない。

TL;DR

この記事が参考になった方
ここここからチャージや購入してくれると嬉しいです(ブログ主へのプレゼントではなく、ご自身へのチャージ)
欲しいもの / Wish list

目次

  1. はじめに
  2. TL;DR
  3. 環境・条件
  4. 詳細
    1. 前置き
    2. 結論(実現方法)
      1. 補足
  5. まとめ
  6. その他・メモ
  7. 参考文献

環境・条件

1
2
3
4
$ sw_vers
ProductName: macOS
ProductVersion: 11.1
BuildVersion: 20C69
  • Google Chrome バージョン: 87.0.4280.88(Official Build) (x86_64)

詳細

前置き

以下はとあるプロジェクトの要件など。

  • Cordova で iOS/Android まとめて開発
  • コンテンツ内部は先方が作成
    • コンテンツ内に先方管理外のサイトへのリンクがある
  • ガワはこちらで作成して、コンテンツを iframe で読み込む
  • iframe 内のリンクをシステムデフォルトブラウザで開きたい

iOS は問題なかった(意図通りに動作した)が、Android だけ上手く動かなかった。具体的には、リンクをタップすると iframe 内で開こうとするが、X-Frame-Options の設定により net::ERR_BLOCKED_BY_RESPONSE となる、というもの。

この記事でまとめる方法と、apache/cordova-plugin-inappbrowser とを組み合わせることで解決できたので、その話は別記事にまとめた。

この記事では、その前段階として、iframe と親 Window との間での通信方法について整理。

結論(実現方法)

ざっくり書くと以下。

iframe 側(child.html)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div id="send-message">
send message
</div>
<script>
const div = document.getElementById('send-message');
div.addEventListener('click', () => {
if (!window.parent) {
return;
}

// できれば第2引数は適切な origin 指定をすべき
window.parent.postMessage('hello', '*');
});
</script>

親 Window 側(parent.html)

1
2
3
4
5
6
7
8
9
10
11
12
<iframe id="parent" src="child.html"></iframe>
<script>
window.addEventListener('message', event => {
// 実際には適切な origin 判定が必要
// ローカルファイルを Chrome でそのまま開くと origin = 'null' になっている
if (event.origin !== 'null') {
return;
}

alert(event.data);
});
</script>

補足

origin の 指定/判定 について

(特別な理由がなく、origin が分かるのであれば) origin の 指定/判定 を行うべき。

  • postMessage の第2引数(targetOrigin) で対象 origin の指定が可能
  • メッセージ受信ハンドラ内で event.origin で判別が可能
送受信データについて

送られてきたデータを元に条件分岐など、複雑な処理を実現したい場合は JSON.stringify, JSON.parse で相応のデータを送受信すれば良い。

1
2
3
4
5
6
7
8
9
10
// 子側
const sendData = { a: 1, b: [2, 3, 4] };
window.parent.postMessage(JSON.stringify(sendData), '*');

// 親側
window.addEventListener('message', event => {
// 略
const recvData = JSON.parse(event.data);
// 略
});

まとめ

その他・メモ

以下などで「iframe 内の要素に対しても addEventListener でイベントハンドラ設定できる」みたいな記述があったが、(自分が試した限りでは)実現できなかった。(ちなみに自分は jQuery でのやり方は試していない)

ただ、自分が間違っていた可能性もありそうなので、また気が向いた時に試すかも。

参考文献

関連記事

この記事が参考になった方
ここここからチャージや購入してくれると嬉しいです(ブログ主へのプレゼントではなく、ご自身へのチャージ)
欲しいもの / Wish list