标准参考

关于 HTML 4.01 规范中 onload 内在事件说明:http://www.w3.org/TR/html401/interact/scripts.html#adef-onload

关于 DOM Level2 Events 规范中 load 事件说明:http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-eventgroupings-htmlevents

问题描述

插入空白页面 IFRAME 元素时 Chrome Safari Opera 浏览器中会触发 load 事件。

造成的影响

Chrome Safari Opera 浏览器中,在插入 "src" 属性未设置或设置为空字符串的 IFRAME 元素后立即修改其 "src" 属性值,会导致 IFRAME 标记绑定的 load 事件再被触发。

触发 IE 和 Firefox 浏览器中 IFRAME 标记 "src" 属性值的历史记录问题。

受影响的浏览器

所有浏览器  

问题分析

根据规范说明,load 事件可以作用于 FRAMESET 标记中,因此同样也可以作用于 IFRAME 标记上。它表示着 IFRAME 内页面已经完全加载完毕 IFRAME 标记处于可用状态。

如果创建的 IFRAME 标记没有设定 "src" 属性和值,那么他的 load 事件是否会被触发呢?

分析以下代码:

function iframeLoad(){
alert("IFRAME 标记的 onload 事件触发");
}
function addEvent(eventName,element,fn){
if (element.attachEvent) element.attachEvent("on"+eventName,fn);
else element.addEventListener(eventName,fn,false);
}
window.onload = function (){
var iframe = document.createElement('iframe');
addEvent("load",iframe,iframeLoad);
document.body.appendChild(iframe);
iframe.src="iframe.html"; }

代码中动态创建了 IFRAME 标记,为其监听 load 事件,此时还没有显示性的设定他的 "src" 值就将他加入文档树中。此后立即为 IFRAME 设置 "src" 属性,指向具体的 URL 。

观察各浏览器中运行效果:

  IE Firefox Chrome Safari Opera
IFRAME onload 事件触发次数 1次 2次

看到 Chrome Safari Opera 中 onload 事件被触发两次。

为了搞清这个问题,我们需要知道没有设置 src 属性的 IFRAME 被添加到 DOM 树中后,其默认的 "src" 值是什么。继续分析以下代码:

function iframeLoad(iframe){
document.body.appendChild(document.createTextNode("IFRAME URL : "+iframe.location.href));
}
function addEvent(eventName,element,fn){
if (element.attachEvent) element.attachEvent("on"+eventName,fn);
else element.addEventListener(eventName,fn,false);
}
window.onload = function (){
var iframe = document.createElement('iframe');
addEvent("load",iframe,function (){iframeLoad(iframe.contentWindow)});
document.body.appendChild(iframe);
}
  所有浏览器
URL about:blank

这 里将空 src 值 IFRAME 标记内调用页面的 URL 打印出来,可以发现所有浏览器中处理一致,均为 "about:blank" 。这个页面是个空 HTML 文档页,所有浏览器均内置提供。这个空页面被加载完成后同样会触发 IFRAME 标记的 onload 事件。

由 此可以推测,是否由于 Chrome Safari Opera 浏览器中当 IFRAME 标记被插入文档树后,载入"about:blank" 页面速度非常快立即就触发了 load 事件,以至于还没来得及执行为他指定新 URL 的语句;当新 URL 指定后,当前页面加载完成时又触发了一次 IFRAME 标记的 load 事件,这样总共就触发了两次。

而其他浏览器则是载入 "about:blank" 页花费时间加多,页面并未完全加载时其 URL 已经被改变,因此相对 Chrome Safari Opera 浏览器第一次 load 事件并没有触发,只有等新 URL 中的页面加载完毕后 load 事件才被触发,这样总共只触发了一次。

为了证明以上猜测,将一段延时执行的代码加入其中:

function iframeLoad(iframe){
var src = (iframe.src)?iframe.src:iframe.contentWindow.location.href;
document.body.appendChild(document.createElement("br"));
document.body.appendChild(document.createTextNode("IFAME 标记 src 值为 "+ src + " 的 onload 事件触发"));
}
function addEvent(eventName,element,fn){
if (element.attachEvent) element.attachEvent("on"+eventName,fn);
else element.addEventListener(eventName,fn,false);
}
window.onload = function (){
var iframe = document.createElement('iframe');
addEvent("load",iframe,function (){iframeLoad(iframe)});
iframe.src= "about:blank";
document.body.appendChild(iframe);
setTimeout(function (){iframe.src="iframe.html";},300)
}

代码中,在 IFRAME 节点被添加到文档树树后,延时 300 毫秒再改变它的 src 属性,以便给其他浏览器充足的事件将 "about:blank" 页面加载完成。

此时各浏览器执行结果一致:

  所有浏览器
IFRAME onload 事件触发次数 'about:blank' 页面1次
'iframe.html' 页面1次
共2次

这 个结果证明了之前的猜想:Chrome Safari Opera 浏览器执行速度比想象中的要快的多,导致好像“多”触发了一次 load 事件,实际上所有浏览器均会为 IFRAME 标记内每个页面触发他的 load 事件,前提是让这些页面有足够的事件加载完成。

【注】:使用appendChild 方法将没有设置 src 属性的 IFRAME 插入文档树和使用 innnerHTML 方式将没有写 src 属性的 IFRAME 标记字符串插入文档树时,均会存在以上分析的问题。

最后来看,上面的代码中在插入节点之前为 IFRAME 标记显式性的设置了 src 属性值为 "about:blank" 的页面,这是为了避免 Firefox 中 URL 缓存的 Bug。

在 IE 和 Firefox 中,如果 IFRAME 没有显示性的设置 "src" ,如果该页面第一次被打开,则实际页面的 src 值为 "about:blank";否则将为 IFRME 标记中最后一个被设定的 "src" 值。

分析以下代码(没有明确定义 src 属性值):

window.onload = function (){
var iframe = document.createElement('iframe');
addEvent("load",iframe,function (){iframeLoad(iframe)});
document.body.appendChild(iframe);
setTimeout(function (){iframe.src="iframe.html";},300)
}

注意代码 "src" 值最初未定义,最终被修改为 "ifarme.html",观察在各浏览器中运行结果:

  Chrome Safari Opera IE Firefox
首次显示 'about:blank' 页 onload 事件触发
'iframe.html' 页 onload 事件触发
F5 普通刷新 'about:blank' 页 onload 事件触发
'iframe.html' 页 onload 事件触发
'iframe.html' 页 onload 事件触发
'iframe.html' 页 onload 事件触发
Ctrl + F5 强制刷新 'about:blank' 页 onload 事件触发
'iframe.html' 页 onload 事件触发

可见,IE 和 Firefox 浏览器中出现了 IFRAME 元素的 "src" 属性最后指向的记忆问题,普通刷新页面后,没有明确设置 "src" 属性的 IFRAME 标记将默认使用上一条历史记录中的 "src" 值。

解决方案

为 IFRAME 标签的 src 属性指定具体 URL 后再将节点插入 DOM 树中 。

本文转自:http://www.w3help.org/zh-cn/causes/SD9019

iframe onload事件触发两次的更多相关文章

  1. 解决label点击事件触发两次问题

    问题描述: 通常,为了用户体验,我们点击单选框或者复选框后面文字,即可选中当前项.代码如下: <label> <input type="radio" name=& ...

  2. 解决jQuery中dbclick事件触发两次click事件

    首先感谢这位小哥!http://qubernet.blog.163.com/blog/static/1779472842011101505853216/ 太长姿势了. 在jQuery事件绑定中,dbc ...

  3. 解决Chrome Safari Opera环境下 动态创建iframe onload事件同步执行

    我们先看下面的代码: setTimeout(function(){ alert(count); },2000); var count = []; document.body.appendChild(c ...

  4. java swing 按钮事件触发两次或者多次

    按钮事件触发多次? 如果是JButton,八成是由于粗心,多次添加了监听事件 保持只添加一个监听事件就解决了~

  5. IScroll中div点击事件触发两次解决办法

    1.网上的同学说的,直接修改源代码,但是这种方法可能会影响到现有的程序. 搜索onBeforeScrollStart方法,将其中的preventDefault禁止掉搜索_end方法,将其中模拟clic ...

  6. tap 事件会触发两次问题

    因项目中使用 coffeeScript (http://coffee-script.org/),此处记录下用 coffeeScript 语法解决 tap 事件触发两次的问题. 在 id="b ...

  7. js iframe onload &line-height浏览器兼容问题

    1.IE iframe onload事件 在IE下给iframe添加onload事件经常无效,因为在IE下它最多只能被激活一次,而且无论你有多少个iframe,被激活的也只能是最后一个的.可以用下面的 ...

  8. IFRAME动态加载触发onload事件(转)

    原文地址:http://blog.ops.cc/webtech/javascript/f5nhm.html <body> <script>var iframe = docume ...

  9. 浏览器返回按钮不会触发onLoad事件

    最近在做一个移动端项目,发现移动端某些返回和PC端是有差异的, 比如ios中返回按钮是直接使用缓存的, 不会执行任何js代码, 这个问题很蛋疼, 例如, 在提交的时候将按钮设置为loading状态, ...

随机推荐

  1. 并查集-G - 食物链

    G - 食物链 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A.现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种 ...

  2. ET框架之SceneChangeComponent

    初始化事件 using ETModel; namespace ETHotfix { [Event(EventIdType.InitSceneStart)] public class InitScene ...

  3. java面试题错题集(牛客网错题)

    一.关于Object类的说法正确 Java中所有的类都直接或间接继承自Object,无论是否明确的指明,无论其是否是抽象类. Object的equals方法,只有一句话,return this==ob ...

  4. 从零开始教你做高保真原型图+UI 设计规范

    编者按:<从零开始设计App>系列到这篇已经是第三期了,上期是低保真原型图,这期@Sophia的玲珑阁 聊聊如何从零开始制作高保真原型图和UI 设计规范. 往期回顾: <设计师怎样从 ...

  5. Jquery动态改变my97datepicker的日期形式

    先要解绑触发事件: $('#start').unbind('focus'); 然后再绑定触发事件: $('#start').bind('focus',function(){WdatePicker({s ...

  6. AcWing 913. 排队打水

    #include <iostream> #include <algorithm> using namespace std; typedef long long LL; ; in ...

  7. Drf小结

    DRF框架 一. 认识restful架构 REST,即Representational State Transfer的缩写 ,我们一般叫他'表现层状态转化' REST的路径设计思路是简洁: 资源(比如 ...

  8. Apache Kafka(四)- 使用 Java 访问 Kafka

    1. Produer 1.1. 基本 Producer 首先使用 maven 构建相关依赖,这里我们服务器kafka 版本为 2.12-2.3.0,pom.xml 文件为: <?xml vers ...

  9. 【13】堆排序 最小K个数

    题目 输入整数数组 arr ,找出其中最小的 k 个数.例如,输入4.5.1.6.2.7.3.8这8个数字,则最小的4个数字是1.2.3.4. 收获 优先队列实现 (n1,n2)->n2-n1是 ...

  10. calloc函数的使用和对内存free的认识

    #include<stdlib.h> void *calloc(size_t n, size_t size): free(); 目前的理解:  n是多少个这样的size,这样的使用类似有f ...