zoukankan      html  css  js  c++  java
  • 不使用定时器实现iframe的自适应高度

    在微博上看到有人提及不使用定时器实现iframe自适应(onReadyStateChange + onLoad + onResize + onDOMSubtreeModified),然后就去折腾了,这篇与之前的文章:《不使用定时器实现onhashchange》有点类似

    /*****此方法暂时只支持同域下,跨域的问题有待解决****/

    以往要使iframe的高度自适应,往往用定时器在跑,这个方法不错。但如果遇到这样的场景,可能会有点问题,就是某个页面嵌入一个app页面(iframe),

    而这个app页面,可能经常会发生一些dom的更改,而且是由成千上万的第三方开发者开发的。而且如果定时器一直开着(只要iframe存在),总归不太好~

    这样就面临着一个问题:

    开发者可能需要对DOM进行修改,而iframe的高度如果需要改变,就必须由第三方开发者调用父层的,每一处DOM修改都要调用一次…

    把调整iframe高度的方法暴露给第三方开发者,显示不大合适。有没有更好的方法,有,那就是DOMSubtreeModified。

    在折腾的过程中,其实遇到了很我问题,不过基本上通过google就可以解决掉。某人讲的话还是挺有道理的:“Web前端开发无难点,贵在研究问题的精神和过程,方法论只是结果,价值观才是精髓~”

    这个属于DOM 3 Level的事件,关于此事件的详情,可以参考以下网址:

    MDC DOMSubtreeModified >>

    W3C DOMSubtreeModified>>

    相应的还有DOMAttrModified、DOMNodeInserted、DOMNodeRemoved等等事件

    举个DOMSubtreeModified的简单例子:

       1: /**
       2:  * ( modified from Nicholas's book )
       3:  */
       4: (function() {
       5:     var _EventUtil = {
       6:         /**
       7:          * 注册event handler
       8:          */
       9:         addHandler: function( element, type, handler ) {
      10:             if( element.addEventListener ) {
      11:                 element.addEventListener( type, handler, false );
      12:             } else if( element.attachEvent ) {
      13:                 element.attachEvent( 'on' + type, handler );
      14:             } else {
      15:                 element[ 'on' + type ] = handler;
      16:             }
      17:         },
      18:         /**
      19:          * 停止event capturing and bubbling
      20:          */
      21:         preventDefault: function( event ) {
      22:             if( event.preventDefault ) {
      23:                 event.preventDefault();
      24:             } else {
      25:                 event.returnValue = false;
      26:             }
      27:         },
      28:         /**
      29:          * 获取事件触发的事件源
      30:          */
      31:         target: function( event ) {
      32:             return event.target || event.srcElement;
      33:         },
      34:         /**
      35:          * 获取event对象
      36:          */
      37:         event: function( event ) {
      38:             return event || window.event;
      39:         }
      40:     }
      41:     window.EventUtil = _EventUtil;
      42: })();

    页面内容

       1: <a href="#" id="show">Show</a>
       2: <div style="display: none;" id="sqr1">
       3: </div>

    绑定的事件:

       1: var attrChangeListener = function( elem, fn ) {
       2:     EventUtil.addHandler( elem, 'DOMSubtreeModified', fn );
       3: };
       4:  
       5: EventUtil.addHandler( window, 'load', function() {
       6:     var showElem = document.getElementById( 'show' );
       7:     var sqr1 = document.getElementById( 'sqr1' );
       8:     
       9:     EventUtil.addHandler( showElem, 'click', function() {
      10:         if( sqr1.style.setAttribute ) {
      11:             sqr1.style.setAttribute( 'display', 'block' );
      12:         } else {
      13:             sqr1.setAttribute( 'style', 'display:block;' );
      14:         }
      15:     } )
      16:     
      17:     attrChangeListener( sqr1, function( event ) {
      18:         alert( EventUtil.target( event ) );
      19:         alert( event.type );
      20:         alert( 'Attrubute Name:' + ( event.attrName || '' ) );
      21:         alert( 'Attribute Change:' + ( event.attrChange || '' ) );
      22:         alert( 'Previous value:' + ( event.prevValue || '' ) );
      23:         alert( 'New value:' + ( event.newValue || '' ) );
      24:     } );
      25: } );
      26:         

    在线预览地址>>  请使用Firefox进行查看

    解决iframe自适应高度的问题,比较理想的办法是:

    iframe的onload前使用定时器修改iframe的高度,在onload后清除定时器,然后监听iframe它的document的DOMSubtreeModified事件。为什么在onload之前还要使用定时器呢?防止iframe页面加载资源过久,页面的高度显示上会有问题。而监听DOMSubtreeModified事件的主要作用是为了省去在iframe内修改dom时,每一次都要主动调用一次修改iframe高度的方法。这样就让iframe开发者,只需要专注自身页面的逻辑结构,不用再考虑每修改dom之处都要调用修改iframe高度的方法。

    注明:文章的标题是不使用定时器,而上面我提到定时器,主要是担心iframe的domready与onload的那段时间内,iframe的高度看上去会很怪异(实际开发中这一段时间有多长,影响有多大,到底要不要加定时器,还是需要根据实际情况再衡量一下)

    下面的实现,我没有考虑使用定时器(如果加上了就不符合文章的标题了,而在实际开发中可能还是需要,视情况而定了),关于使用定时器使iframe自适应高度,可以参考口碑的那篇文章:再谈iframe自适应高度>>

    还有一点要提一下:chrome的某些版本中,子页(iframe)调用parent时会被禁止,而导致页面没有效果,放在web上跑就好了。这个问题可以参考这里找到说明,地址>>

    下面直接上代码了,代码中有参考老外的例子,在整理过程中没有及时的保存这些链接,有空再补上。

    例子是index.html嵌入iframe.html页面,index.html代码:

       1: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
       2: <html xmlns="http://www.w3.org/1999/xhtml">
       3:  <head>
       4:   <title>iframe 高度自适应的例子</title>
       5:   <meta name="generator" content="editplus" />
       6:   <meta name="author" content="" />
       7:   <meta name="keywords" content="" />
       8:   <meta name="description" content="" />
       9: <meta http-equiv="content-type" content="text/html;charset=utf-8" />
      10:   <style type="text/css">
      11:     *  {margin:0; padding:0;}
      12:     body {background-color:#fff; padding:20px;}
      13:     iframe {border:1px solid #406c99; 600px;}
      14:     button {position:absolute; left:20px; top:20px; 80px;}
      15:   </style>
      16:  </head>
      17:  
      18:  <body>
      19:   <button onclick="createFrame()">创建iframe</button>
      20:  </body>
      21: </html>
      22: <script type="text/javascript">
      23: function createFrame() {
      24:     document.getElementsByTagName("button")[0].disabled = true;
      25:  
      26:     frameHandler.create();
      27: }
      28:  
      29: var frameHandler = function() {
      30:     var inner;
      31:     
      32:     var _iframeName = "iframe_iden_1";
      33:  
      34:     return inner = {
      35:         _isSupport : false,
      36:         init : function() {
      37:             
      38:         },
      39:         create : function() {
      40:             var frame = null;
      41:  
      42:             if (window.ActiveXObject) {
      43:                 frame = document.createElement('<iframe name="'+_iframeName+'">');
      44:             } else {
      45:                 frame = document.createElement("iframe");
      46:                 frame.setAttribute("name", _iframeName);
      47:             }
      48:             
      49:             frame.setAttribute("id", _iframeName);
      50:             frame.frameBorder = "none";
      51:             frame.scrolling = "no";
      52:             frame.style.marginTop = '40px';
      53:             
      54:             document.body.appendChild(frame);
      55:  
      56:             frame.contentWindow.focus();
      57:  
      58:             inner.check();
      59:             
      60:             if (inner._isSupport) {
      61:                 if (!frame.addEventListener) {
      62:                     frame.attachEvent("onload", function() {
      63:                         frame.detachEvent("onload", arguments.callee);
      64:                         inner.adjustFrameHeight();
      65:                         frame.contentWindow.attachEvent("onresize", inner.adjustFrameHeight);                        
      66:                     });
      67:                     
      68:                 } else {
      69:                     frame.addEventListener("load", function() {
      70:                         frame.removeEventListener('load', arguments.callee, false);
      71:                         inner.adjustFrameHeight();
      72:                         frame.contentWindow.document.documentElement.addEventListener('DOMSubtreeModified', inner.adjustFrameHeight, false);
      73:                     }, false);
      74:                 }
      75:             } else if (frame.addEventListener) {// for FF 2, Safari 2, Opera 9.6+
      76:                     frame.addEventListener("load", function() {
      77:                         var fn = arguments.callee;
      78:                         setTimeout(function() {
      79:                             frame.removeEventListener('load', fn, false);
      80:                         }, 100);
      81:                         
      82:                         inner.adjustFrameHeight();    
      83:                         frame.contentWindow.document.documentElement.addEventListener('DOMNodeInserted', inner.adjustFrameHeight, false);
      84:                         frame.contentWindow.document.documentElement.addEventListener('DOMNodeRemoved', inner.adjustFrameHeight, false);
      85:                     }, false);
      86:             }
      87:  
      88:             frame.src = "iframe.html";
      89:         },
      90:         getFrame : function() {
      91:             return document.getElementById(_iframeName).contentWindow;
      92:         },
      93:         adjustFrameHeight : function() {
      94:             var elem = document.getElementById(_iframeName);
      95:  
      96:             elem.style.height = Math.max(elem.contentWindow.document.body.scrollHeight, elem.contentWindow.document.documentElement.scrollHeight) + 'px';
      97:         },
      98:         check : function() {
      99:             var remain = 1, 
     100:                 doc = document.documentElement, 
     101:                 dummy;
     102:             
     103:             if (doc.addEventListener) {
     104:                 doc.addEventListener("DOMSubtreeModified", function() {
     105:                     inner._isSupport = true;
     106:                     doc.removeEventListener("DOMSubtreeModified", arguments.callee, false);
     107:                 }, false);
     108:             } else {
     109:                 inner._isSupport = true;
     110:                 return ;
     111:             }
     112:  
     113:             dummy = document.createElement("div");
     114:             doc.appendChild( dummy );
     115:             doc.removeChild( dummy );
     116:         }
     117:     }
     118: }();

    iframe.html的代码:

       1: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
       2: <html xmlns="http://www.w3.org/1999/xhtml">
       3:  <head>
       4:   <title> new document </title>
       5:   <meta name="generator" content="editplus" />
       6:   <meta name="author" content="" />
       7:   <meta name="keywords" content="" />
       8:   <meta name="description" content="" />
       9:   <meta http-equiv="content-type" content="text/html;charset=utf-8" />
      10:   <style type="text/css">
      11:     * {margin:0; padding:0;}
      12:     body { padding:5px; background-color:#fff;}
      13:     button {margin:0 10px;}
      14:   </style>
      15:  </head>
      16:  
      17:  <body>
      18:   xxxxxxxxx
      19:  
      20: <button disabled="true" onclick="start()">Start Interval</button>
      21: <button onclick="stop()">Stop Interval</button>
      22: <button onclick="clearAllChilds()">Clear All</button>
      23:  
      24:  </body>
      25: </html>
      26: <script type="text/javascript">
      27: var g_interval_timer = null;
      28:  
      29: function start() {
      30:     commonHandler(0);
      31:  
      32:     g_interval_timer = setInterval(function(){    
      33:         var div = document.createElement("div");
      34:             div.innerHTML = "<p>dddddddddddddddddddddddddddd</p>";
      35:         document.body.appendChild(div);
      36:     }, 100);    
      37: }
      38:  
      39: function stop() {
      40:     commonHandler(1);    
      41: }
      42:  
      43: function clearAllChilds() {
      44:     stop();
      45:     var childs = document.getElementsByTagName("div");
      46:     
      47:     while (childs.length) {
      48:         document.body.removeChild(childs[0]);
      49:     }
      50: }
      51:  
      52: function commonHandler() {
      53:     var buttons = document.getElementsByTagName("button"),
      54:         idx = arguments[0];
      55:  
      56:     if (g_interval_timer) {
      57:         clearInterval(g_interval_timer);
      58:         g_interval_timer = null;
      59:     }
      60:     
      61:     buttons[idx].disabled = true;
      62:     buttons[1 - idx].disabled = false;
      63: }
      64:  
      65: start();

    下面本地用nginx建了一个域名ajax.com运行的效果:

    IE6(7、8效果与此类似,但不知为何一定要让iframe foucs后才有效果,详见代码)

    image

    Chrome:

    image

    FF:

    image

    Safari:

    image

    Opera:

    image

    完整例子的下载地址>>

  • 相关阅读:
    最近在搞微信支付,说说流程,免得遗忘
    好记性不如烂笔头-Mysql查找如何判断字段是否包含某个字符串
    用jquery操作字体颜色覆盖当前页面的css设置
    页面白屏并且报错PHP Parse error: syntax error, unexpected end of file in 试了很久总算解决了
    bootstrap的datetimepicker.js的结束时间大于开始时间,当前日期之前的代码
    使用ClassLoader类装载器获取系统资源
    关于App class loader的总结
    ClassLoader 详解及用途(写的不错)
    webRequest
    Tomcat学习之ClassLoader
  • 原文地址:https://www.cnblogs.com/meteoric_cry/p/1977773.html
Copyright © 2011-2022 走看看