iframe学习(三)之监听窗口

前言

经常会遇到这样一种情况。

在iframe里嵌入另外一个页面时。如果iframe载入的页面响应较快,或许我们感觉不到页面载入的不同步,但试想,如果一个需要内嵌到iframe里的页面的响应很慢,这里会出现一种什么现象呢?这时将会出现所有页面已经载入完成,但

iframe元素处,将会出现空白,直到内嵌页面完成载入时,该空白处才会显示新载入的页面。可想而知,一个页面如果长时间的空白,对于浏览者来说将意味着什么。如果在内嵌页面未载入完成时,给出一种加载提示信息。如:“页面加载

中”之类的,我想这对浏览页面用户来讲,将不再是煎熬,更是一种视觉上的享受。

为了实现这样的效果,一般会采用如下原理处理。

  • iframe载入区域给出友好的提示信息。
  • 当iframe载入完成时,清空提示信息,而让iframe显示。

这些都比较容易,但现在的问题的关键是怎么监听iframe元素内的页面已经载入完成。

关键这个问题,一般来讲,会分两种情况来讨论解决方案。

  • 同域嵌套:最好是让子页面调用父页面的方法。
  • 异域嵌套:如果是异域,但子页面无法修改,那么:在Firefox/Opera/Safari中,可以直接使用iframe onload事件;而在IE中,可以通过定时器测定子页面的document.readyState,或者使用iframe onreadystatechange事件计算该事件的响应。

一个简单的包含iframe的父页面将是如下样子的:

<!DOCTYPE ...>
<html xmlns="...">
  <head>
  <meta ... />
  <title>Iframe</title>
  <body>
    <iframe name="iframe1"  id="iframe1" width="300" height="50" src="#" ></iframe>
    <script type="text/javascript">//codes here</script>
  </body>
</html>

开始:

一、同域嵌套

调用父页面对象

parent.html

function ifrmLoaded() {
    // code here
}
sub.html

window.onload = function() {
    window.parent.ifrmLoaded();
}

缺点:

  • 子父页面必须在同域中
  • 需对子页面有修改权;或者,可以请负责此子页面的同事为我们添加一段代码
<script type=”text/javascript”>
  if(window.parent!=window) window.parent.iframeCall();
</script>

把它放到window.onlad中,或者直接放在</body>之前。

注[1]:在对iframe或其它窗口性质的前端编程中,同域名是最完美的先天条件。只要在同一域名中,各个窗口间的对象是共享的,我们完全可以自由发挥,在不同的窗口间来回驾驭。总之,只有想不到,没有做不到。

有时候,为了防止自己的页面不被别人嵌套,可以采用如下方式解决:

if(window.parent!=window) window.parent.location="http://hqlong.com";
//or
if(window.top!=window) window.top.location="http://hqlong.com";

二、异域嵌套(或者子页面已存在且无法修改)

在不同域名的页面,浏览器出于安全考虑,几乎完全封锁了页面间的对象来往

在异域的页面嵌套中,子页面总是可以直接改变父窗口的location以防止被嵌套,但父页面对这个一点办法也没有。当然,子页面除了仅仅永恒地拥有父窗口.location的修改权外,也没有其它了。例如,在IE下,子页面只能直接修改父页面

的.location为另一个源:

<script tyle=”text/javascript”>parent.location=”http://anotherPage.com/”;</script>

但无法访问其它对象,如window.name,document等,连location.href等location的子属性就无法访问。当然,在防止嵌套方面,使用top.location会更强大。

方法一:使用onreadystatechange来判断

【Firefox/Opera/Safari中直接使用iframe onload事件】

document.getElementById(‘ifrm‘).onload = function() {
    //here doc
}

【在IE下,注册iframe onreadystatechange事件】

iframe onreadystatechange事件

var oFrm = document.getElementById(‘ifrm‘);
oFrm.onreadystatechange = function() {
    if (this.readyState &amp;&amp; this.readyState == ‘complete‘) {
        onComplete();
    }
}

定时器测document.readyState 

var oFrm = document.getElementById(‘ifrm‘);
var fmState=function(){
    var state=null;
    if(document.readyState){
        try{
            state=oFrm.document.readyState;
        }catch(e){state=null;}
        if(state=="complete" || !state) {
            onComplete();
            return;
        }
        window.setTimeout(fmState,10);
    }
};
//在改变src或者通过form target提交表单时,执行语句:
if(fmState.TimeoutInt) window.clearTimeout(fmState.timeoutInt);
fmState.timeoutInt = window.setTimeout(fmState,400);

每当iframe加载页面,过程内会激活onreadystatechange事件三次,相应的状态分别是loading,interactive和complete,而最后一次才是complete.

问题一:为什么要延时400毫秒?

因为javascript对DOM的操作是异步的,我们必须等待脚本对DOM落实执行后才开始下一步。400秒这个数取决 与客户端的设备和浏览器的响应速度,好的设备的响应速度能在10毫秒以内甚至更快,但100毫秒左右可能比较大众化,400毫秒应该是十分保守的了。总 之,较大的毫秒数能适合更多的用户设备状况,并能减少了客户端设备的工作量。至于document.readyState,指的是iframe内子页的docuent.readyState,而不是父页面的

问题二:为什么使用try和 catch?

因为在异域的情况下,当iframe的子页到达interactive状态时,父页面就会失去访问权,所以最多只能返回到loaded这一步,因此IE出一个未知错误——其实就是没有权限,所以try和catch,让这个错误沉默下去。

兼容Firefox/Opera/Safari/IE的处理方式

var oFrm = document.getElementById(‘ifrm‘);
oFrm.onload = oFrm.onreadystatechange = function() {
     if (this.readyState && this.readyState != ‘complete‘) return;
     else {
         onComplete();
     }
}

或者

var $iFrame=$("#IFrame");
$iFrame.prop("src","http://www.baidu.com");
if (!/*@[email protected]*/0) { //如果不是IE,IE的条件注释  
    $iFrame[0].onload = function(){     
        alert("加载完毕"); 
    };  
}else{  
    $iFrame[0].onreadystatechange = function(){ // IE下的节点都有onreadystatechange这个事件  
         if (iframe.readyState == "complete"){  
            alert("加载完毕"); 
        }  
    };  
}

方法二:使用attachEvent判断

var $iFrame=$("#IFrame");
$iFrame.prop("src","http://www.360.cn");
if ($iFrame[0].attachEvent){  
      $iFrame[0].attachEvent("onload", function(){ // IE  
              alert("加载完毕"); 
      });  
} else {  
      $iFrame[0].onload = function(){ // 非IE  
              alert("加载完毕");  
      };  
}

方法三:使用jquery里的load来判断

var $iFrame=$("#IFrame");      
$iFrame.prop("src","http://www.aijquery.cn");    
$iFrame.load(function(){       
    alert("加载完毕");    
});

注意

上面的方法必须是动态创建iframe或者动态添加iframe指定的src地址的情况下使用

参考

iframe载入完成时的事件监听

jquery里判断iFrame框架是否加载完成的三种方法

跨浏览器的iframe onload 事件监听

原文地址:https://www.cnblogs.com/kunmomo/p/12126403.html

时间: 2024-07-31 09:07:32

iframe学习(三)之监听窗口的相关文章

vue 中监听窗口发生变化,触发监听事件, window.onresize &amp;&amp; window.addEventListener(&#39;resize&#39;,fn) ,window.onresize无效的处理方式

1 // 开始这样写,不执行 2 window.onresize = function() { 3 console.log('窗口发生变化') 4 } 5 6 7 // 改成window监听事件 8 window.addEventListener('resize', function() { 9 console.log('窗口发生变化') 10 }) onresize的定义方式 一.直接在html中定义 如<body onresize="doResize()"/> 二.直接

Vue中监听窗口关闭事件并在窗口关闭前发送请求

Vue中监听窗口关闭事件并在窗口关闭前发送请求,代码如下: mounted() { window.addEventListener('beforeunload', e => this.beforeunloadHandler(e)) window.addEventListener('unload', e => this.unloadHandler(e)) }, destroyed() { window.removeEventListener('beforeunload', e => thi

html学习 - jquery事件监听详解

html学习 - jquery事件监听详解 html学习 - jquery事件监听详解 监听方法 监听方法参数解释 click参数 事件自动执行问题解决 bind方法 live方法 监听方法 在jquery里,监听的方法比较多,用的最多的就是简单的.click() .onchange() .pressdown() 所以这样很简单啊,直接使用就好了,只要符合参数规范就可以了.除了这个还有bind() live() 方法. 而addEventListener()同bind()方法是没有很大功能上的区

Android学习按键事件监听与Command模式

Android学习按键事件监听与Command模式 - Dufresne - 博客园 ? 一 Command模式 意图: 将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化: 对请求排队或记录请求日志,以及支持可撤销的操作. 将请求被封装成一个对象,当向某对象提交请求时,使我们可以不用去知道被具体的请求的操作或者请求的接收者, 实现了动作的请求者对象和动作的执行者对象之间的解耦合. 适用性: 使用Command模式代替callback形式的回调应用: 在不同的时刻指定.排列和执行请

iframe学习(四)之窗口跨域

什么是跨域? 跨域问题是浏览器同源策略限制,当前域名的JavaScript只能读取同域下的页面对象,这也是JavaScript出于安全方面的考虑. 通俗的来说,跨域可以理解为:从一个域名访问另一个域名,出于安全考虑,浏览器不允许这么做. 跨域种类 什么时候我们认为发生了跨域呢?或者说什么情况下“浏览器”是不允许我们访问的呢? 不同域名 - 禁止 例子:http://www.baidu.com 与 http://www.h5course.com 不同子域 - 禁止 例子:http://www.ba

html学习 - javascript事件监听以及addEventListener参数分析

事件监听 在Javascript中事件的监听是用来对某些操作做出反应的方法.例如监听一个按钮的pressdown, 或者获取鼠标左键按下时候鼠标的位置.这些都需要使用监听来完成.监听的函数很简单:addEventListener. 这里解释一下一个网页的嵌套关系:最外层:window 包含:document 包含:html 包含: body 包含:div等等... addEventListener监听方法 按钮监听事件响应 首先我们需要获取一个按钮的handle,获取的方法很简单,代码如下: v

React监听窗口变化事件

功能说明:本例子采用MUI table组件 + React实现. 需求描述:固定表头,列表高度随浏览器窗口的改变而改变.(本例中当窗口高度小于472像素后,便不作限制) 实现简介:1.监听浏览器窗口,每当窗口大小发生改变,给列表高度重新复制: 2. 列表高度通过state来管理. 关键代码: 窗口监听事件管理: 列表高度处理函数: 组件里的设置: 效果图(关键项涂了马赛克...) 窗口高于472px: 窗口高度低于472px(列表边上的滚动条不见了,取而代之的浏览器窗口的滚动条,木有截下来)

安卓开发学习日记 DAY5——监听事件onClick的实现方法

今天主要学习了监听事件的是实现方法,就是说,做了某些动作后,怎么监听这个动作并作出相应反应. 方法主要有三种: 1.匿名内部类的方法 2.独立类的方法 3.类似实现接口的方法 以下分别分析: 1.匿名内部类的方法 就是使用innerClass的方式创建监听事件 步骤如下: 1)创建一个button,在xml中拖入一个button即可 2)在源程序中对button进行初始化 就是,先创建一个button btn,然后使用findViewById找到你之前的那个button进行关联,此时请注意fin

spring boot 学习 ---- 使用事件监听

spring 的事件监听 事件监听其实我们并不陌生,简单来讲,当程序达到了某个特定的条件,程序就会自动执行一段指令.在spring 中也一样,我们可以使用spring中的事件监听来实现某些特定的需求. 发布事件 既然要监听事件,首先要发布我们的事件嘛.在spring中发布事件我们可以通过继承ApplicationEvent 来发布我们的事件类. @Data public class SendEvent extends ApplicationEvent { public SendEvent(Obj