

■事象  
iframeを動的に作成(createElement)して、  
addEventListenerに「DOMContentLoaded」を追加しているが、  
iframeのsrc先のDOM読み込み完了時にイベントが発生しません。

■コーディング

[code]

    var parent_obj = document.getElementById("top");
    var obj = document.createElement('iframe');
    
    if(obj.addEventListener){
        obj.addEventListener("DOMContentLoaded",xxx);//★これが発火しない
        //obj.addEventListener("load",xxx);//☆遅い
    }else if(obj.attachEvent){
        obj.attachEvent("onload",xxx);
    }else{
        obj.onload = xxx;
    }
    
    parent_obj.appendChild(obj);
    obj.src = "URL";
    
    function xxx(e){
        alert("発火");★これが発火しない
    }
    
[/code]

■やりたい事  
addEventListener("load",xxx)だと画像読み込み後にイベントが発生するので、遅いです。  
iframeのソースが返ってきた直後にイベントを呼びたいのです。

■質問  
なぜDOMContentLoadedが発火しないのでしょうか。  
コーディングが悪いのでしょうか？

それともcreateElement('iframe')はDOMContentLoadedのイベントに対応していないのでしょうか？  
その場合、上記【やりたい事】の代案はございますでしょうか？


CC BY-SA 3.0
2016-12-11T02:22:05.283
31078
2017-03-23T03:24:16.540
2017-01-10T16:48:23.933
8000
19734
question
javascript html
iframeのDOMContentLoadedが発火しません


`HTMLIFrameElement`には`contentWindow`および`contentDocument`というプロパティが存在しますので、そちらのイベントを拾えばよいのではないでしょうか。

[code]

    obj.contentDocument.addEventListener("DOMContentLoaded",xxx);
    
[/code]


CC BY-SA 3.0
2016-12-11T02:48:54.627
31079
2016-12-11T02:48:54.627
5750
31078
answer


まず`DOMContentLoaded`は`Window`に対して発火するイベントですのでiframe要素に対して使うことはできません。

クロスオリジンの場合は、iframe側のページのHTTPヘッダやスクリプトを操作する必要があります。  
それができない場合は以下の手法は使えません…、というより恐らく不可能です。

### 手法1. 双方のドキュメントのドメインを合わせる

もし親側とiframe側の上位ドメインが共通であれば、次のスクリプトでページドキュメントのドメインを上位ドメインに合わせるだけで目的を達成できます。

[code]

    document.domain = "your-domain.com";
    
[/code]

参考: [同一オリジンポリシー#オリジンの変更 -
MDN](https://developer.mozilla.org/ja/docs/Web/Security/Same-
origin_policy#Changing_origin)

共通の上位ドメインがない場合は、次の手法2か3に頼ります。

### 手法2. iframe側に親側のオリジンからの操作を許可する

iframe側のHTTPヘッダーを書き加えられる場合は、次のヘッダーをサーバーサイドから出力してください。

[code]

    Access-Control-Allow-Origin: http://your-parent-page.com
    
[/code]

### 手法3. postMessageを使う

若干面倒ですがクロスドメイン通信が可能な`window.postMessage`でなんとかします。  
挙動などの詳細は [window.postMessage -
MDN](https://developer.mozilla.org/ja/docs/Web/API/Window/postMessage)
を参考にしてください。

親ページ:

[code]

    window.addEventListener("message", messageCallback, false);
    
    function messageCallback(event) {
      if (event.origin !== "http://your-iframe-page.com") return;
      if (event.data === "iframe loaded!") {
        /* ロード完了 */
        alert("発火");
      }
    }
    
[/code]

iframeページ:

[code]

    window.addEventListener("DOMContentLoaded", loadedCallback, false);
    
    function loadedCallback(event) {
      window.parent.postMessage("iframe loaded!", "http://your-parent-page.com");
    }
    
[/code]


CC BY-SA 3.0
2017-02-16T10:41:07.270
32723
2017-02-16T13:04:44.607
2017-02-16T13:04:44.607
19925
19925
31078
answer