Подтвердить что ты не робот

Динамически создаваемые iframe триггеры события onload дважды

Я создал iframe динамически и обнаружил, что это событие iframe запускает событие onload дважды.

var i=0;
frameOnload=function(){
  console.log(i++);  
};

var ifr=document.createElement("iframe");  
ifr.src="javascript:(function(){document.open();document.write('test');document.close();})();";
ifr.onload=frameOnload;  
document.body.appendChild(ifr);

Почему я, наконец, 1?
Как предотвратить iframe onload дважды вместо того, чтобы указывать onload-функцию на null внутри себя?

4b9b3361

Ответ 1

Я также столкнулся с одной и той же проблемой, но не получаю ответа нигде, поэтому сам тестировал.

Событие onload iframe будет запускаться дважды в браузерах webkit (сафари/хром), если вы присоедините событие onload до того, как iframe будет добавлен в тело.

Таким образом, вы можете предотвратить onrame onload дважды, изменив свои коды следующим образом.

document.body.appendChild(ifr);
ifr.onload=frameOnload; // attach onload event after the iframe is added to the body

Затем вы получите только одно событие onload, которое является событием, которое действительно загрузило документ.

Ответ 2

Более подробно об ответе с наибольшим количеством голосов: если вы не можете контролировать, когда и как объекты подключаются к DOM - например, при использовании инфраструктуры (у нас это происходило в нашем приложении Angular), - вы можете захотеть попробуйте решение ниже.

Я провел evt.target.src межбраузерное тестирование и нашел следующий обходной путь: проверьте параметр, переданный evt.target.src onload и проверьте evt.target.src в evt.target.src событий.

iframe.onload = function(evt) {
    if (evt.target.src != '') {
        // do stuff
    }
}

(если вы вызываете глобальный метод из HTML, не забудьте передать event в вашей разметке HTML: <iframe onload="window.globalOnLoad(event)">)

evt.target.src может быть '' (пустая строка) только в webkit при первом вызове onload.

Изучение поведения нагрузки iframe в различных ситуациях

iframe.onload = function(evt){
    console.log("frameOnload", ++i);
    console.log("src = '" + evt.target.src + "'");
};

поведение загрузки iframe с обычным URL

// Chrome:  onload 1 src='', onload 2 src=requestedSrc
// IE11:    onload 1 src=requestedSrc
// Firefox: onload 1 src=requestedSrc
document.body.appendChild(iframe);
iframe.src = "http://www.example.org/";

поведение загрузки iframe с 404 URL

// Chrome:  onload 1 src='', onload 2 src=requestedSrc
// IE11:    onload 1 src=requestedSrc
// Firefox: onload 1 src=requestedSrc
document.body.appendChild(iframe);
iframe.src = "http://www.example.org/404";

поведение загрузки iframe с неразрешимым (на уровне DNS) URL

// Chrome:  onload 1 src='', onload 2 src=requestedSrc
// IE11:    onload 1 src=requestedSrc
// Firefox: onload NEVER triggered!
document.body.appendChild(iframe);
iframe.src= 'http://aaaaaaaaaaaaaaaaaaaaaa.example/';

Поведение iframe.src onload с iframe.src явно установленным в about:blank перед добавлением в DOM

// Chrome:  onload 1 src='about:blank', onload 2 src=requestedSrc
// IE11:    onload 1 src=requestedSrc
// Firefox: onload 1 src=requestedSrc
iframe.src = "about:blank";
document.body.appendChild(iframe);
iframe.src = "http://www.example.org/";

Поведение iframe.src onload с iframe.src явно установленным на выражение javascript перед добавлением в DOM

// Chrome:  onload 1 src='javascript:void 0', onload 2 src=requestedSrc
// IE11:    onload 1 src=requestedSrc
// Firefox: onload 1 src=requestedSrc
iframe.src = "javascript:void 0";
document.body.appendChild(iframe);
iframe.src = "http://www.example.org/";

Ответ 3

FWIW, в то время как я смог воспроизвести double onload, в случае, если iframe.src - javascript:, я не смог воспроизвести его с помощью обычного HTTP-URL (одна загрузка выполнялась один раз). Однако при изменении порядка вызовов, чтобы iframe.src устанавливался после добавления в тело, тогда происходит двойная загрузка (опять же, только webkit):

var i = 0;

var iframe = document.createElement("iframe");
iframe.onload = function(){
  console.log("frameOnload", ++i);
};
document.body.appendChild(iframe);
iframe.src = "http://www.example.org/";
//iframe.src = "http://www.example.org/404";

// double onload!

Когда я назначаю src перед добавлением, я получаю один вызов onload.

var i = 0;

var iframe = document.createElement("iframe");
iframe.onload = function(){
  console.log("frameOnload", ++i);
};
iframe.src = "http://www.example.org/";
//iframe.src = "http://www.example.org/404";
document.body.appendChild(iframe);

// only one onload

Ответ 4

У меня такое случалось с асинхронно загруженными таблицами стилей, как этот.

<link rel="preload" href="stylesheet.css" as="style" onload="this.rel='stylesheet'">

Я считаю, что самое простое решение - удалить само событие:

<link rel="preload" href="stylesheet.css" as="style" onload="this.removeAttribute('onload'); this.rel='stylesheet'">

Ответ 5

Вот код, который работает хорошо!

Предоставлено: @Dave Stolie https://coderanch.com/t/443223/languages/Frames-loading-refresh.

<html>  
 <head>  
   <script type="text/javascript">  
     function loadFrame()  
     {
        var url="http://www.google.com";
        alert(document.getElementById("theFrame").src);

        if (document.getElementById("theFrame").src != url)
        {
            alert("loading");
            document.getElementById("theFrame").src = url;  
        }
     }  
   </script>  
   </head>  
   <body onLoad="loadFrame();">  
   <iframe id="theFrame" src="x"/>
  </body>  
  </html>