2016-05-06 3 views
2

В IE мы можем прослушать onreadystatechange событие, когда document.write изменяет содержимое iframe. Но в Chrome это не работает.В Chrome, как узнать, когда document.write изменяет содержимое iframe?

<html> 
<script> 
function loadFrame() { 
    var ifr = document.getElementById("iframeResult"); 
    var ifrw = (ifr.contentWindow) ? ifr.contentWindow : (ifr.contentDocument.document) ? ifr.contentDocument.document : ifr.contentDocument; 
    ifrw.document.open(); 
    ifrw.document.write("<input type='submit' />"); 
    ifrw.document.close(); 
} 
</script> 
<body onload="loadFrame();"> 
<div><input type="submit" value="Reload Frame" onclick="loadFrame()" /></div> 
<div> 
    <iframe frameborder="0" id="iframeResult" style="background-color:red;" onreadystatechange="console.log('ready state changed');"> 
    </iframe> 
</div> 
</body> 
<html> 

В коде выше, когда нажмите кнопку Reload Frame на IE, выходы пульта ready state changed, но в Chrome, он не выводит ничего.

Как мы должны делать в Chrome знать, когда document.write изменяет содержимое iframe?

EDIT:

Гидеон прав, мы можем слушать onload события в Chrome. Но если я прокомментирую document.open и document.close две строки, onload больше не работает. У кого-нибудь есть решение?

+0

Это может быть лучший ответ: [http://stackoverflow.com/a/14570614/1790154](http://stackoverflow.com/a/14570614/1790154). –

ответ

0

Этот код делает трюк:

<script> 
var observeDOM = (function(){ 
    var MutationObserver = window.MutationObserver || window.WebKitMutationObserver, 
     eventListenerSupported = window.addEventListener; 

    return function(obj, callback){ 
     if(MutationObserver){ 
      // define a new observer 
      var obs = new MutationObserver(function(mutations, observer){ 
       if(mutations[0].addedNodes.length || mutations[0].removedNodes.length) 
        callback(); 
      }); 
      // have the observer observe foo for changes in children 
      obs.observe(obj, { childList:true, subtree:true }); 
     } 
     else if(eventListenerSupported){ 
      obj.addEventListener('DOMNodeInserted', callback, false); 
      obj.addEventListener('DOMNodeRemoved', callback, false); 
     } 
    } 
})(); 

window.onload = function() { 
    // Observe a specific DOM element: 
    observeDOM(document.getElementById("iframeResult").contentDocument ,function(){ 
     console.log('dom changed'); 
    }); 
} 

function reload() { 
    document.getElementById("iframeResult").contentDocument.write("<div>abc</div>"); 
} 
</script> 
<body> 
<input type="submit" onclick="reload();" value="Reload" /> 
<iframe id="iframeResult"></iframe> 
</body> 

быть в курсе, что наблюдатель должен быть добавлены к document, не document.body. Потому что первый звонок document.write() будет автоматически звонить document.open(), он покроет старый document.body с новым.

1

Вы можете добавить прослушиватель событий load, который будет запущен, когда iFrame будет изменен страницей.

document.getElementById("iframeResult").addEventListener("load", function(){ 
    console.log("iFrame has been loaded."); 
}); 
+0

Да, это действительно работает. Но если я комментирую 'document.open' и' document.close' две строки, это больше не работает. Вы знаете, как с этим бороться? –

+0

@MartinZhai Почему вы хотите прокомментировать эти строки? Событие 'onload' не будет запускаться, если в нем ничего не загружено. –

+0

'document.open' очищает текущий DOM, который запускает' onload'. Если мы не выполним 'document.open',' document.write' добавит элементы в существующий DOM, а 'onload' не будет запущен. В моем случае мне нужно знать, когда 'document.write' изменяет содержимое iframe. Необходимо либо рассмотреть ситуацию. –

1

Я думаю, что придумал решение вашей проблемы. Он включает использование MutationObserver API, чтобы обнаружить изменения в DOM iFrame.

MutationObserver предоставляет разработчикам способ реагировать на изменения в DOM . Он предназначен для замены событий мутаций, определенных в спецификацией событий DOM3.

Я также использовал window.postMessage API уведомить родительскую страницу, когда MutationObserver обнаружил события DOM, таким образом, чтобы родитель, чтобы ответить.

Я создал простой пример ниже. Обратите внимание, что я использовал * для происхождения, но рекомендуется проверить происхождение по соображениям безопасности. Также обратите внимание, что Chrome не разрешает кадры обращаться к другим фреймам в локальной файловой системе, но он будет работать на веб-сервере или вы можете протестировать локально с помощью FireFox, который не имеет этого ограничения.

iframe.html

<head> 
    <meta charset="utf-8"> 
</head> 

<body> 

    <script> 
     var observer = new MutationObserver(function(mutations) { 
      mutations.forEach(function(mutation) { 
       if (mutation.type == 'childList') { 
        if (mutation.addedNodes.length >= 1) { 
         if (mutation.addedNodes[0].nodeName != '#text') { 
          window.parent.postMessage("DOMChanged", "*"); 
         } 
        } else if (mutation.removedNodes.length >= 1) { 
         window.parent.postMessage("DOMChanged", "*"); 
        } 
       } else if (mutation.type == 'attributes') { 
        window.parent.postMessage("DOMChanged", "*"); 
       } 
      }); 


     }); 

     var observerConfig = { 
      attributes: true, 
      childList: true, 
      characterData: true 
     }; 

     // listen to all changes to body and child nodes 
     var targetNode = document.body; 
     observer.observe(targetNode, observerConfig); 
    </script> 
</body> 

index.html

<!DOCTYPE html> 
<html lang="en"> 

<head> 
    <meta charset="utf-8"> 
</head> 

<body> 
    <div> 
     <input type="submit" value="Update iFrame" onclick="updateiFrameDOM()" /> 
    </div> 
    <iframe src="iframe.html" id="iframeResult"></iframe> 

    <script> 
     function updateiFrameDOM() { 
      var ifr = document.getElementById("iframeResult"); 
      var ifrw = (ifr.contentWindow) ? ifr.contentWindow : (ifr.contentDocument.document) ? ifr.contentDocument.document : ifr.contentDocument; 

      var div = document.createElement("div"); 
      var text = document.createTextNode("Hello"); 
      div.appendChild(text); 

      var body = ifrw.document.getElementsByTagName("body")[0]; 
      body.appendChild(div); 

     } 

     // Create IE + others compatible event handler 
     var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent"; 
     var eventer = window[eventMethod]; 
     var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message"; 

     // Listen to message from child window 
     eventer(messageEvent, function(e) { 
      console.log(e.data); 
     }, false); 
    </script> 

</body> 

</html> 

Некоторые дополнительные источники я использовал:

Respond to DOM Changes with Mutation Observers

window.postMessage Tip: Child-To-Parent Communication

Я надеюсь, что это поможет вам.

+0

Работает на FF. Но если я изменил 'body.appendChild' на' document.write', он больше не работает. Хотя, вы предоставляете возможность взглянуть. Я сделаю некоторые исследования, если мы сможем наблюдать изменения DOM в Chrome. Благодарю. –

+0

@MartinZhai Он работает в Chrome, но должен выполняться на веб-сервере вместо локальной файловой системы. Мой фрагмент кода прослушивается на 'document.body', поэтому, вероятно, он не записывает изменения через' document.write'. Поиграйте и посмотрите, что вы придумали. Надеюсь, мое решение помогло вам. Я сам кое-чему научился. –

+0

Да, это помогает. Я нашел еще один полезный ответ [здесь] (http://stackoverflow.com/a/14570614/1790154). –

Смежные вопросы