我动态创建了一个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?
我也遇到了同样的问题,但是到处都没有答案,所以我自己测试了一下。
如果您在 iframe 附加到正文之前附加 onload 事件,则 iframe onload 事件将在 webkit 浏览器( safari/chrome )中触发两次。
因此,您可以通过以下方式更改代码来防止 iframe 加载两次。
document.body.appendChild(ifr);
ifr.onload=frameOnload; // attach onload event after the iframe is added to the body
那么,你只会得到一个onload事件,这是文档真正加载的事件。
扩展投票最高的答案:如果您无法控制事物何时以及如何附加到 DOM - 例如,当使用框架时(我们在 Angular 应用程序中发生过这种情况)-- 您可能想尝试下面的解决方案。
我进行了大量的跨浏览器测试,发现了以下解决方法: 检查传递给
onload
回调的参数并在事件侦听器中检查 evt.target.src
。
iframe.onload = function(evt) {
if (evt.target.src != '') {
// do stuff
}
}
(如果您从 HTML 调用全局方法,请记住在 HTML 标记中传递
event
:<iframe onload="window.globalOnLoad(event)">
)
根据我的测试,evt.target.src
只能在第一个''
调用中的webkit中为onload
(空字符串)。
iframe.onload = function(evt){
console.log("frameOnload", ++i);
console.log("src = '" + evt.target.src + "'");
};
// 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/";
// 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";
// 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/';
在追加到 DOM 之前,iframe.src
显式设置为
about:blank
的 iframe 加载行为
// 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 onload 行为,在附加到 DOM 之前将
iframe.src
显式设置为 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/";
<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'">
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
信用:@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>
从框架内部,
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
}
即使在 Internet Explorer 中,这种行为似乎也是一致的(除了没有
.addEventListener
我通过检查 event.target.url 是否与 iframe 的 onload 函数内的 src url 匹配来处理它。
<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>
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")
}
}
Angular 的解决方案
发生这种情况是因为如果您在 iframe 附加到正文之前附加 onload 事件,则 iframe onload 事件将在 webkit 浏览器( safari/chrome )中触发两次。
使用AfterViewInit hook 注册加载回调
模板:
<iframe
#iframe
[src]="src | safe : 'resourceUrl'"
[height]="height"
width="100%"
></iframe>
成分:
export class IframeWrapperComponent implements AfterViewInit {
@Input({ required: true }) src = '';
@Input({ required: true }) title = '';
@Input({ required: true }) height = '';
@ViewChild('iframe') iFrame!: ElementRef<HTMLIFrameElement>;
ngAfterViewInit(): void {
if (this.iFrame) {
this.iFrame.nativeElement.onload = () => {
console.log('write your onload logic here');
};
}
}
}