iframe重复下载问题解决方案

17 篇文章 0 订阅
  Vue.prototype.createDownloadUrl = function(url) {
            // //获得id为downLoadListFrame的frame
            var divFrame = window.parent.document.getElementById("downLoadListFrame")
            //判断是否存在,如果存在先移除,再重新创建
            if (divFrame != null) {
              window.parent.document.body.removeChild(divFrame)
            }

            // var iframe = window.parent.document.createElement("iframe");
            // iframe.setAttribute("id", "downLoadListFrame");
            // //download_file.id = "downFrame";
            // window.parent.document.body.appendChild(iframe);
            // divFrame = window.parent.document.getElementById("downLoadListFrame");
            // //隐式调用,(注意:window.parent.document 适应对于,farme内部代码,调用frame 外部dom;如果项目未用frame,改写成 document即可)
            // divFrame.src = url;
            // divFrame.style.display = "none";
            //重新创建
            var iframe = document.createElement('iframe');
            iframe.setAttribute("id", "downLoadListFrame");
            addEvent("load",iframe,function (){iframeLoad(iframe)});
            iframe.src= url
            // iframe.src= "about:blank";
            document.body.appendChild(iframe);
            setTimeout(function (){iframe.src='';},1000)
          }
          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);
          }

标准参考

关于 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);
}
 所有浏览器
URLabout: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 树中 。

参见

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值