标准参考

关于 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. Allegro 反射仿真--IBIS模型转化

    一.IBIS模型的获取 a) 直接找芯片供应商 b) 从网上下载 i.到Google网站直接搜索某个型号的IBIS模型: ii. 到器件厂商的官方网站下载: iii.从专门提供IBIS模型的网站搜索下 ...

  2. valign

    值 描述 top 对内容进行上对齐. middle 对内容进行居中对齐(默认值). bottom 对内容进行下对齐. baseline 与基线对齐.

  3. (转)GC ROOTS

    还是英文的技术博客更给力,更清楚,本人懒,没有翻译. In your specific example, in any managed environment, Person is not a GC ...

  4. 通过属性选择器找元素,可以通过$(__).length是否为0来判断是否找到了元素

    通过属性选择器找元素,可以通过$("").length是否为0来判断是否找到了元素. 为0的时候表示没有找到,其余则返回找到了多少个. 不能通过$("")是否为 ...

  5. 2019-08-04 纪中NOIP模拟B组

    T1 [JZOJ3403] 数列变换 题目描述 小X看到堆成山的数列作业十分头疼,希望聪明的你来帮帮他.考虑数列A=[A1,A2,...,An],定义变换f(A,k)=[A2,A3,...,Ak,A1 ...

  6. CI框架Email类发送邮件提示Unable to send data: . The following SMTP error was encountered: Unable to .......

    最近服务器迁移,然后CI框架做的项目发邮件全挂掉了,刚开始是25端口没开,然后开了正好还是有问题, 1.打印请求信息和返回信息 echo $this->email->print_debug ...

  7. 总结下抽象类Abstract和虚方法Virtual(易混点)

    1.普通类中可以有普通方法和虚方法,在被继承时,虚方法可以选择重写(override)或者不重写 2.抽象类中可以有普通方法和虚方法和抽象方法,当被继承时 如下 1.普通方法不能被子类重写 2.虚方法 ...

  8. django 0

    web 框架的本质 - socket服务端 socket 收发消息 根据不同的路径返回不同的内容 模板渲染 jinja2 字符串替换 mvc model(模型/db) view(展示html) con ...

  9. MFC单文档视图中嵌入GLFW窗口

    开始学习OpenGL由于有一段时间,但是glfw只有窗口区,虽然通过某种手段(移步这里)可以加入工具栏,但仍然无法作为一个标准的GUI,而直接在MFC或Qt里面使用OpenGL API感觉有诸多制肘, ...

  10. echarts相关问题记录

    1.图标距离容器边界 //echats options options : { //... grid : { top : 40, //距离容器上边界40像素 bottom: 30 //距离容器下边界3 ...