标准参考

关于 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. js面向对象的程序设计 --- 中篇(创建对象) 之 工厂模式和 构造函数模式

    创建对象 虽然Object构造函数或对象字面量都可以用来创建单个对象,但这些方式有个明显的缺点:使用同一个接口创建很多对象,会产生大量重复代码. ·工厂模式 工厂模式是一种广为人知的设计模式,这种模式 ...

  2. 跨表更新,Mysql Update Join

    背景 项目新导入了一批人员数据,这些人的有的部门名称发生了变化,有的联系方式发生了变化,暂且称该表为t_dept_members, 系统中有另外一张表 t_user_info 记录了人员信息. 要求将 ...

  3. 计算机网络,HTTP - 头部中带X前缀的头部字段

    HTTP中,什么是"X-" Prefix header? 例如 github API 的response headers有很多X前缀的头部: 查一下MDN文档: Custom pr ...

  4. count(*)、count(1)、count(column)的区别

    count(*)对行的数目进行计算,包含NULL count(column)对特定的列的值具有的行数进行计算,不包含NULL值. count()还有一种使用方式,count(1)这个用法和count( ...

  5. PHP Apache/Nginx/IIS等各环境下的伪静态配置

    一.Apache的伪静态配置 1.网站根目录下需要有 .htaccess 文件,没有则自己创建一个,内容如下: <IfModule mod_rewrite.c> RewriteEngine ...

  6. docker dial unix /var/run/docker.sock: connect: permission denied

    Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker. ...

  7. Oracle空表的分配segment

      1.查询相关参数deferred_segment_creation select * from v$parameter where name='deferred_segment_creation' ...

  8. python numpy中sum()时出现负值

    import numpy a=numpy.random.randint(1, 4095, (5000,5000)) a.sum() 结果为负值, 这是错误的,a.sum()的类型为 int32,如何做 ...

  9. 【做题笔记】P1042 乒乓球

    坑 #1:输入有若干行,但处理的时候要看成一个整体的信息.比如说第一行最后一局比分是 2:1 ,这时不算比完,这个比分要继承到第二行的信息中继续处理. 坑 #2:一局结束,当且仅当其中一方比分大于等于 ...

  10. python面试的100题(1)

    题目:有一个jsonline格式的文件file.txt大小约为10K def get_lines(): with open('file.txt','rb') as f: return f.readli ...