javascript 动态创建的iframe触发onload事件两次

axr492tv  于 2022-12-28  发布在  Java
关注(0)|答案(8)|浏览(175)

我动态创建了一个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?

nfs0ujit

nfs0ujit1#

我也遇到过同样的问题,但没有得到任何答案,所以我自己测试.
在webkit浏览器(safari/chrome)中,如果在iframe附加到主体之前附加onload事件,则iframe onload事件将触发两次。
因此,您可以通过以下方式更改代码来防止iframe onload两次。

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

然后,您将只获得一个onload事件,这是文档真正加载的事件。

d8tt03nd

d8tt03nd2#

下面是得票最多的答案:* 如果您无法控制何时以及如何将内容附加到DOM--例如,当使用框架时 (我们在Angular应用程序中遇到过这种情况)-- 您可能需要尝试下面的解决方案。*
我做了大量的跨浏览器测试,发现了以下变通方案:* * 检查传递给onload回调的参数,并在事件侦听器中检查evt.target.src。**

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

(if如果你从HTML调用全局方法,记得在HTML标记中传递event<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 + "'");
};

带常规URL的iframe加载行为

// 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 URL的iframe加载行为

// 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加载行为,URL不可解析(在DNS级别)

// 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加载行为,其中iframe.src在追加到DOM之前显式设置为about:blank

// 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加载行为,其中iframe.src在追加到DOM之前显式设置为javascript表达式

// 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/";
epfja78i

epfja78i3#

异步加载的样式表也遇到过这种情况,比如下面这个。

<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'">
wko9yo5t

wko9yo5t4#

顺便说一句,当iframe.srcjavascript:时,我可以重新生成两个onload,但是不能用普通的HTTP URL重新生成(onload只发生一次)。然而,当您更改调用顺序,使iframe.src在附加到body之后设置时,就会发生双重加载(同样,仅限于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
mcdcgff0

mcdcgff05#

这里的代码工作得很好!
署名:@戴夫·斯托利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>
dbf7pr2w

dbf7pr2w6#

基于@jakub.g的回答:
在框架内部,evt.target.src hack不起作用,但是我发现我可以检查evt.target.title,第二次DOMContentLoaded被触发时,evt.target指向正在加载的文档,所以下面的代码可以起作用:

document.addEventListener('DOMContentLoaded', function(evt) {
  if (evt.target.title !== myPageTitle) {
    // Work around for Webkit browsers trigging this event twice om iframes
    return
  }
  // DOM content loaded, for real
}

即使在InternetExplorer中,这种行为似乎也是一致的(保存没有.addEventListener的旧版本

pes8fvy9

pes8fvy97#

我在vue.js 2.6.12中遇到过这个问题
我通过检查event.target.url是否与iframe的onload函数中的srcurl匹配来处理它。

<template>
           <iframe
                @load="onLoad"
                :src="embedUrl"
                ref="cardNumber"
                frameborder="0"
                scrolling="no"
                width="100%"
                height="100%"
                align="left"
            ></iframe>
</template>

<script>
export default {
...,
methods: {
onLoad (event) {
    // considerting iframe to be loaded if the event.target.url matches the src url
    if(event.target.src === this.embedUrl)) {
      // instructions after loading
    } 
   }
 }
}
</script>
gkl3eglg

gkl3eglg8#

Register for onload event after appending iframe. This solves my problem.
document.body.appendChild(ifr);
ifr.onload=frameOnload;  

E.G:
iframeContainer.appendChild(iframe)
  iframe.onload = function() {
    console.log("iframe onload called")
  iframeContainer.appendChild(iframe)
  iframe.onload = function() {
    console.log("iframe onload called")
  }  
    
  }

相关问题