zoukankan      html  css  js  c++  java
  • 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 (!/*@aijquery@*/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 事件监听

  • 相关阅读:
    HTML 防盗链 用src引用网上图片显示 403 Forbidden
    JS C# 正则表达式去除html字符中所有的标签(img em标签除外)
    net core 3.1使用ElasticSearch 全文搜索引擎
    VS2019开启调试,测试图片上传的时候,一点到图片上传,直接导致VS调试崩掉,返回 程序“[14764] iisexpress.exe”已退出,返回值为 -1 (0xffffffff)。 是什么原因导致的?
    NET 5 使用IdentityServer4 4.x
    服务器下配置springboot项目开机自启
    分布式技术文档
    win10系统ffmpeg命令初体验
    大数据Hadoop生态圈介绍
    MySQL之Explain详解
  • 原文地址:https://www.cnblogs.com/kunmomo/p/12126403.html
Copyright © 2011-2022 走看看