iframe 动态onload事件处理方式

转自:http://w3help.org/zh-cn/causes/SD9022

标准参考

关于 HTML 4.01 规范中 BODY 标记的 onload 属性说明: http://www.w3.org/TR/html401/struct/global.html#h-7.5.1

关于 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

问题描述

页面加载完成后会触发 onload 事件,通常下会使用 window.onload 、 document.body.onload、 HTMLIFrame.onload 方法来处理他;但是各浏览器对页面 onload 事件处理方式并不一致,这些方法可能会导致页面加载完成后无法触事件处理函数。

造成的影响

window.onload 与 document.body.onload 事件相互关系不明确。

IE6 IE7 IE8 中无法通过为属性赋值方式为 IFRAME 元素绑定 load 事件处理函数。

受影响的浏览器

IE6 IE7 IE8 Firefox  

问题分析

一、window.onload 与 document.body.onload 事件以及 BODY 标签内的内联 onload 事件,三者相互关系不明确

有关这两个事件在 W3C 指定的规范中并没有说明其区别,由于 window 对象属于 BOM 范畴没有统一规范可依,各浏览器对其在此处的实现存有差异。

在微软的 MSDN 中说明 document.body.onload 属性是 window 的 onload 事件处理程序。其它浏览器厂商并没有对此属性做更细致解释。

分析以下代码:

<button onclick="alert(document.body.onload);">查看本页 document.body.onload 事件</button>
<button onclick="alert(window.onload);">查看本页 window.onload 事件</button>
<button onclick="alert(window.onload===document.body.onload);">查看document.body.onload 事件与 window.onload 事件是否为同一事件</button>
<br />
<script>
document.body.onload = function (){ // 函数 A
  document.getElementById("A").innerHTML = "document.body.onload 被触发";
}
window.onload = function (){ // 函数 B
  document.getElementById("B").innerHTML = "window.onload 被触发";
}
</script>
<span id="A" style="background:gold"></span>
<span id="B" style="background:gray"></span>

代码中分别对两种 onload 属性赋值了不同的事件处理函数。其中 window.onload 先于 document.body.onload 被定义。如果他们两者使用的是同一事件处理源,则会发生 window 对象中 onload 事件定义被 body 的事件处理函数所覆盖。

实际上个浏览器运行结果如下:

  IE6 IE7 IE8 Firefox Chrome Safari Opera
实际运行 window.onload 被触发
document.body.onload 事件函数 函数 B 函数 A 函数 B
window.onload 事件函数 null 函数 B
两者事件处理函数是否一致 Flase Flase true

初步可以看出:

  • 在 IE 中 window.onload 事件函数即使定义了,也会是 null ,它的事件处理函数始终是为 document.body.onload 提供的;
  • 在 Firefox 中 document.body.onload 事件不与 window.onload 事件相同,后者事件函数不会覆盖前者;
  • 在 Chrome Safari Opera 中 document.body.onload 事件处理函数被后声明的 window.onload 事件处理函数覆盖。

为了更明确以上猜测,我们将两个事件处理函数位置对调后再来观察实际效果:

window.onload = function () // 函数 B{
  document.getElementById("B").innerHTML = "window.onload 被触发";
}

document.body.onload = function (){ // 函数 A
  document.getElementById("A").innerHTML = "document.body.onload 被触发";
}

这次试图使用 document.body.onload 事件处理函数来覆盖 window.onload,实际运行结果如下:

  IE6 IE7 IE8 Firefox Chrome Safari Opera
实际运行 document.body.onload 被触发 window.onload .onload 被触发 document.body.onload 被触发
document.body.onload 事件函数 函数 A 函数 A 函数 A
window.onload 事件函数 null 函数 B
两者事件处理函数是否一致 Flase Flase true

可以看出:

  • 无论如何在 IE 中 window.onload 事件函数即使定义了,也会是 null ,它的事件处理函数始终是为 document.body.onload 提供的。
  • 在 Firefox 中 只有 window.onload 事件会触发页面加载完成事件,document.body.onload 只是个由用户扩展的方法,并不触发相应事件处理函数。这也说明了为什么仅在 Firefox 浏览器中,两者"事件"函数均被保留。
  • 在 Chrome Safari Opera 中页面加载完成事件由 document.body.onload 和 window.onload 两者的事件处理函数定义顺序有关,后定义的覆盖之前定义的,两者最终会使用同一事件源函数处理事件内容。

在实际应用中 onload 事件还可能被写在 BODY 标签的属性内,而不在脚本标签中定义他的处理函数。此时代码如下:

<script>
window.onload=function(){
  alert("window onload");
}
</script>
<body >

此用例中首先在脚本标签内为 window.onload 事件附加了处理函数,然后有在 BODY 标签内写入 onload 事件处理代码。如果 BODY 标签内的 onload 事件处理与 window.onload 事件处理不同,就会弹出两次对话框,并且可以根据对话框出现的顺序判断哪个 onload 事件处理在前。反之则只会弹出一个对话框,如果仅出现 "window onload" 字样提示就说明 BODY 标签内 onload 属性无效,如果出现 “overridden window onload” 提示就说明 BODY 标签内 onload 事件与 window.onload 事件为同一事件处理机制,后者覆盖了前者。

各浏览器运行结果如下:

  IE6 IE7 IE8 Firefox Chrome Safari Opera
实际运行 ”overridden window onload“
两者均代表 window onload 事件 true

可见,在所有浏览器中均将,BODY 标签内的内联 onload 事件处理等同与 window.onload 事件处理。

结合上文说明可知, Firefox 中 BODY 标签内的 onload 事件属性与脚本标记内写入的 document.body.onload 事件并不一致。

二、IE6 IE7 IE8 中无法通过为属性赋值方式为 IFRAME 元素绑定 load 事件处理函数

某些情况下可能需要为 IFRAME 标记动态添加 onload 监听事件,其实现方法有通常有三种:

  1. 直接为 HTMLIFrameElement.onload 属性为 IFRAME 标记赋值事件处理函数
  2. 使用 HTMLIFrameElement.setAttribute 方法为 IFRAME 标记赋值事件处理函数
  3. 使用事件监听方式为 IFRAME 的 onload 事件绑定处理函数

根据 DOM 规范推荐使用第三种处理方式,但是由于规范在不断修正添加中,浏览器开发时可能相应的标准规范并未出现或者并不完善,这导致了各个版本浏览对此问题的实现差异。

以下将依次分析这三种方式在各浏览器内的处理情况。

1.直接为 HTMLIFrameElement.onload 属性为 IFRAME 标记赋值事件处理函数

分析以下代码:

<body>
<div id="msgA">通过 HTMLIFrameElement.onload 属性动态加入事件处理函数的 IFRAME 没有触发 onload 事件。</div>
<div id="msgB">静态 IFRAME 没有触发 onload 事件。</div>
<br />
<script>

function iframeLoadA(){
  document.getElementById("msgA").innerHTML = "通过 HTMLIFrameElement.onload 属性动态加入事件处理函数的 IFRAME 已经触发 onload 事件。";
}
function iframeLoadB(){
  document.getElementById("msgB").innerHTML = "静态 IFRAME 已经触发 onload 事件。";
}

window.onload = function (){
  var iframeB = document.getElementById("ifarmeB");
  var iframeA = document.createElement(‘iframe‘);
  iframeA.onload = iframeLoadA;
  document.body.appendChild(iframeA);
}

</script>
<iframe id="ifarmeB" ></iframe>
</body>

页面中存在两个 IFRAME 标记,ifrmaeA 标记为动态生成,并且动态为其 onload 属性赋值了加载完成后的处理函数。而 iframeB 标记则是在页面中静态存在的,其 onload 属性对应的事件处理函数已经被固定写入。

运行此代码,在各个浏览器中效果如下:

  IE6 IE7 IE8 Firefox Chrome Safari Opera
HTMLIFrameElement.onload = Function 没有触发 onload 事件 触发 onload 事件
静态 onload 属性定义 触发 onload 事件

可见,在 IE 浏览器中通过 HTMLIFrameElement.onload 属性赋值方式无法响应 IFRAME 标记的 onload 事件。而其他浏览器均支持此写法。

2.使用 HTMLIFrameElement.setAttribute 方法为 IFRAME 标记赋值事件处理函数

将以上代码稍作修改,将 HTMLIFrameElement.onload 赋值语句部分修改为 HTMLIFrameElement.setAttribute方法:

window.onload = function (){
  var iframeB = document.getElementById("ifarmeB");
  var iframeA = document.createElement(‘iframe‘);
  iframeA.setAttribute("onload","iframeLoadA()");
  document.body.appendChild(iframeA);
}

此时 ifrmaeA 标记的 onload 属性以及事件处理函数被 DOM 标准方法 setAttribute 写入。

运行此代码,在各个浏览器中效果如下:

  IE6 IE7 IE8(Q) IE8(S) Firefox Chrome Safari Opera
HTMLIFrameElement.setAttribute 没有触发 onload 事件 触发 onload 事件
静态 onload 属性定义 触发 onload 事件

可见,在 IE 系列浏览器中仅有 IE8(S) 支持通过 setAttribute 方法为 IFRAME 标记写入 onload 属性以及其事件处理函数。而其他浏览器均支持此写法。

3.使用事件监听方式为 IFRAME 的 onload 事件绑定处理函数

再将以上代码稍作修改,使用 DOM 规范中推荐的事件监听绑定方法为 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 iframeB = document.getElementById("ifarmeB");
  var iframeA = document.createElement(‘iframe‘);
  addEvent("load",iframeA,iframeLoadA);
  document.body.appendChild(iframeA);
}

代码中为了兼容 IE 私有的事件绑定方式,封装了名为 addEvent 的处理函数,他为 IE 和其他浏览器提供不同的事件绑定方法,以达到兼容效果。

运行此代码,在各个浏览器中效果如下:

  IE6 IE7 IE8(Q) IE8(S) Firefox Chrome Safari Opera
onload 事件监听绑定 触发 onload 事件
静态 onload 属性定义

此时所有浏览器中为 IFRAME 标记动态绑定的 onload 事件处理方法均生效。

综合以上三种常见情况可以得出结论,除 IE 以外的浏览器均支持对以上三种动态定义 onload 事件处理函数的方法,而所有 IE 系列浏览器对 HTMLIFrameElement.onload 属性的赋值不被支持,他们可以通过 DOM 标准方法 setAttribute 来为 HTMLIFrameElement 类型元素设置 onload 属性,但是由于 IE8 以下版本对 setAttribute 方法支持有限,导致仅 IE8(S) 下生效。最终 IE 浏览器只能通过事件监听方式为 HTMLIFrameElement 类型元素绑定 onload 事件处理函数。

解决方案

  1. 统一为 window 对象的 onload 事件绑定函数,避免在 Firefox 中产生 document.body.onload 事件理解歧义。
  2. 统一使用 DOM 规范的事件监听方法(或 IE 专有事件绑定方法)为 IFRAME 标记绑定 onload 事件处理函数。
时间: 2024-10-11 21:05:58

iframe 动态onload事件处理方式的相关文章

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

原文地址:http://blog.ops.cc/webtech/javascript/f5nhm.html <body> <script>var iframe = document.createElement("IFRAME"); document.body.appendChild(iframe); iframe.src = "http://www.ops.cc"; if (iframe.attachEvent) { iframe.attac

iframe动态创建及释放内存

最近参与一个项目的开发,由于项目是基于浏览器的胖客户端(RIA)应用程序,页面中大量调用iframe.后期测试发现浏览器内存一直居高不下,而且打开iframe页面越多内存占用越大,在IE系列浏览器中尤其明显.所有打开的iframe页面即使关闭了,内存使用也没有明显的下降,IE浏览器在内存占用达到400M左右就变得很卡.分析发现是iframe没有释放造成的,于是对所有已关闭的iframe所占用的内存进行释放,虽然不能完全释放,但是iframe内存占用量不会一直增长,整个应用内存使用量控制在150M

google谷歌浏览器iframe中onload

我想要在报表下载时打开一个遮罩,下载响应给客户端的时候关闭遮罩.这个看似简单的简单的功能需求,在google浏览器测试时遇到了阻碍. 我预想的代码大致是这样的: var export= document.getElementById("export");export.width = 0;export.height = 0; export.innerHTML = '<iframe id="frameId"  src ="'+url+'" wi

window/body/img/iframe 的onload事件

在html页面中,只有body,img,iframe这一类标签具有onload事件. onload事件表示在当前元素载入完成后发生的事件.其中,window也有onload事件,但是跟body的是同一事件,如果页面上对两者都定义了该事件,只会响应一个. iframe上的事件在ie6下有一些bug: 1.iframe的onload事件跟window.onload事件只能二者取其一,似乎ie把它看作同一个事件了!例如: window.onload=function(){ alert("window

IE IE8 iframe的onload方法分析 IE浏览器onload事件失效

判断iframe是否加载完成的完美方法 IE 支持 iframe 的 onload 事件,不过是隐形的,需要通过 attachEvent 来注册. 第二种方法比第一种方法更完美(采用readystatechange判断),因为 readystatechange 事件相对于 load 事件有一些潜在的问题. 这里感觉说的并不是完全准确,开始给我造成了很大的困扰.看其代码才明白,真正意义上来讲IE在创建一个新的iframe时的onload方法需要使用attachEvent来绑定,而原来就存在的ifr

iOS 播放gif动态图的方式探讨

原文链接:http://my.oschina.net/u/2340880/blog/608560 摘要iOS中没有现成的接口来展示gif动态图,但可以通过其他的方式来处理gif图的展示.iOS中播放gif动态图的方式探讨 一.引言 在iOS开发中,UIImageView类专门来负责图片数据的渲染,并且UIImageView也有帧动画的方法来播放一组图片,但是对于gif类型的数据,UIImageView中并没有现成的接口提供给开发者使用,在iOS中一般可以通过两种方式来播放gif动态图,一种方式是

Android学习笔记(36):Android的两种事件处理方式

Android提供了两种事件处理的方式:基于回调的事件处理 和 基于监听的事件处理. 我们来说的容易理解一点: (1)基于回调的事件处理就是继承GUI组件,并重写该组件的事件处理方法.除了一些特定的情况,大部分情况使用基于回调的事件处理方式并不是最好的选择. (2)基于监听的事件处理就是在监听器中定义事件的处理方式,再为组件绑定监听器.这种方式无疑是更能够体现面向对象思想的. 基于回调的事件处理: View类包含如下的方法可以用于重写: boolean onKeyDown(int keyCode

使用动态分区分配方式的模拟

1实验目的 (1)了解动态分区分配方式中使用的数据结构和分配算法 (2)加深对动态分区存储管理方式及其实现过程的理解. 2实验内容 (1)分别实现采用首次适应算法和最佳适应算法的动态分区分配过程alloc()和回收过程free().其中,空闲分区通过空闲分区链来管理:在进行内存分配时,系统优先使用空闲区低端的空间. (2)假设初始状态下,可用的内存空间为640KB,并有下列的请求序列: •作业1申请130KB. •作业2申请60KB. •作业3申请100KB. •作业2释放60KB. •作业4申

iframe之onload事件小记

项目上做了一个具有wizard(向导)功能的菜单导航页面,子页面的引入通过主页面上iframe的src属性切换实现.为了有个良好的交互体验,每次更新iframe的src时,主页面上都显示一个模态的loading效果,等iframe指定的页面加载完后,再通过iframe的onload回调来隐藏loading效果. 常规的代码如下: 点击菜单项时,调用setUrl传入需要载入的子页面url,显示loading效果,页面加载完毕,隐藏loading效果.看起来好像没有什么问题. 由于该项目浏览器兼容性