zoukankan      html  css  js  c++  java
  • iframe onload事件触发两次

    标准参考

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

  • 相关阅读:
    ActiveMQ的作用总结(应用场景及优势)
    深入剖析ThreadLocal实现原理以及内存泄漏问题
    Java ThreadLocal 原理分析
    关于iview ui的"Page分页"组件的使用
    使用TortoiseGit操作分支的创建与合并
    乐观锁与悲观锁的区别
    Linux下如何安装MongoDB及配置
    centos8安装图解(超详细教程)
    SpringBoot整合MongoDB
    PPT学习---醍醐灌顶!你对PPT的理解过时了!
  • 原文地址:https://www.cnblogs.com/gs456/p/11269362.html
Copyright © 2011-2022 走看看