親 Window で iframe からのデータ受信、イベント検出する方法
はじめに
親 Window で iframe
から送られてきたデータを受信したり、iframe
内のイベントを検出する方法。
※イベント検出もデータ送受信機能で実現しているので、厳密にはイベント検出(addEventListener
相当)ではない。
TL;DR
iframe
側からwindow.postMessage
でデータ送信targetOrigin
を適切に指定(可能なら)
- 親 Window 側で
addEventListener('message', handler)
で受信ハンドラ設定event.origin
で送信元をチェック
iframe
で読み込むサイトが管理外の場合は実現不可(のはず)- その他・メモを参照
目次
環境・条件
1 | $ sw_vers |
- 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
側からwindow.postMessage
でデータ送信- 親 Window 側で
addEventListener('message', handler)
でデータ受信(ハンドラ設定)
iframe
側(child.html
)
1 | <div id="send-message"> |
親 Window 側(parent.html
)
1 | <iframe id="parent" src="child.html"></iframe> |
補足
origin の 指定/判定 について
(特別な理由がなく、origin が分かるのであれば) origin の 指定/判定 を行うべき。
postMessage
の第2引数(targetOrigin
) で対象 origin の指定が可能- メッセージ受信ハンドラ内で
event.origin
で判別が可能
送受信データについて
送られてきたデータを元に条件分岐など、複雑な処理を実現したい場合は JSON.stringify
, JSON.parse
で相応のデータを送受信すれば良い。
1 | // 子側 |
まとめ
iframe
側からwindow.postMessage
でデータ送信targetOrigin
を適切に指定(可能なら)
- 親 Window 側で
addEventListener('message', handler)
で受信ハンドラ設定event.origin
で送信元をチェック
iframe
で読み込むサイトが管理外の場合は実現不可(のはず)- その他・メモを参照
その他・メモ
以下などで「iframe
内の要素に対しても addEventListener
でイベントハンドラ設定できる」みたいな記述があったが、(自分が試した限りでは)実現できなかった。(ちなみに自分は jQuery でのやり方は試していない)
- javascript - Adding click event handler to iframe - Stack Overflow
- javascript - addEventListener to iFrame - Stack Overflow
- Detect Click into Iframe using JavaScript - Stack Overflow
- javascript - Detect click event inside iframe - Stack Overflow
- iframe内のクリックイベントを検知する方法 - @テク野路ジーロード
- JavaScriptでiframe内のDOM要素を取得したり操作する | オウンドメディア | 大阪市天王寺区SOHOホームページ制作 | デザインサプライ-DesignSupply.-
- JavaScript - iframe内をタッチしたらイベントが起きるようにしたい|teratail
- Javascript(jQuery)でiframe内のイベントを親フレームで取得する | 綺麗に死ぬITエンジニア
ただ、自分が間違っていた可能性もありそうなので、また気が向いた時に試すかも。
参考文献
- window.postMessage - Web API | MDN
- MessageEvent - Web API | MDN
- MessageEvent.origin - Web APIs | MDN
- iframeの中のコンテンツの要素やイベントを取得する方法(クロスドメイン対応編) | SeekNext合同会社(シークネクスト)
- ウィンドウを跨いだやり取り
- JavaScript - nuxtでiframe内のイベントを取得したい|teratail
- JSON.stringify() - JavaScript | MDN
- JSON.parse() - JavaScript | MDN
関連記事
- jQuery Select2 で、初期値の設定と選択状態のクリア
- JavaScript で画像をローカルにダウンロード
- JavaScript で複数画像を zip に圧縮してローカルにダウンロード
- HTML img タグで画像が 404 エラーのときに代替画像を表示する方法
- mailto リンクで 宛先/CC/BCC/件名/本文 を指定 (JavaScript サンプルあり)
- Chart.js(vue-chartjs) でツールチップの表示内容を変更
- JavaScript で URL のクエリパラメータを操作する方法
- axios で添付ファイルありのリクエスト(multipart/form-data の POST)