js監聽某個元素高度變化來改變父級iframe的高度

最近需要做一個iframe調用其他頁面內容,這個iframe地址是可變化的,但是裏面的內容高度不確定且裏面內容高度可調整,所以需要通過監聽iframe裏面body的高度變化來調整iframe的高度。

後面發現了一個好用的插件detect-element-resize.js,首先看一下這個插件的介紹:

插件簡介

跨瀏覽器,基於事件,元素調整大小檢測。

簡而言之,此實現不使用內部計時器來檢測大小更改(就像我發現的大多數實現一樣)。它使用scroll大多數瀏覽器上的onresize事件,以及IE10及以下的事件。

使用的方法不僅檢測javascript生成的調整大小更改,還檢測CSS僞類的更改,例如:hover,CSS動畫等。

插件兼容性

Chrome
Firefox
IE 11 及以下 (在11,10,9,8和7上測試)

已知問題

在IE 10及更低版本上:如果分離元素並重新附加它,則需要再次添加調整大小偵聽器。
源代碼

(function () {
    var attachEvent = document.attachEvent,
        stylesCreated = false;
     
    if (!attachEvent) {
        var requestFrame = (function(){
            var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame ||
                                function(fn){ return window.setTimeout(fn, 20); };
            return function(fn){ return raf(fn); };
        })();
         
        var cancelFrame = (function(){
            var cancel = window.cancelAnimationFrame || window.mozCancelAnimationFrame || window.webkitCancelAnimationFrame ||
                                   window.clearTimeout;
          return function(id){ return cancel(id); };
        })();
 
        function resetTriggers(element){
            var triggers = element.__resizeTriggers__,
                expand = triggers.firstElementChild,
                contract = triggers.lastElementChild,
                expandChild = expand.firstElementChild;
            contract.scrollLeft = contract.scrollWidth;
            contract.scrollTop = contract.scrollHeight;
            expandChild.style.width = expand.offsetWidth + 1 + 'px';
            expandChild.style.height = expand.offsetHeight + 1 + 'px';
            expand.scrollLeft = expand.scrollWidth;
            expand.scrollTop = expand.scrollHeight;
        };
 
        function checkTriggers(element){
            return element.offsetWidth != element.__resizeLast__.width ||
                         element.offsetHeight != element.__resizeLast__.height;
        }
         
        function scrollListener(e){
            var element = this;
            resetTriggers(this);
            if (this.__resizeRAF__) cancelFrame(this.__resizeRAF__);
            this.__resizeRAF__ = requestFrame(function(){
                if (checkTriggers(element)) {
                    element.__resizeLast__.width = element.offsetWidth;
                    element.__resizeLast__.height = element.offsetHeight;
                    element.__resizeListeners__.forEach(function(fn){
                        fn.call(element, e);
                    });
                }
            });
        };
         
        /* Detect CSS Animations support to detect element display/re-attach */
        var animation = false,
            animationstring = 'animation',
            keyframeprefix = '',
            animationstartevent = 'animationstart',
            domPrefixes = 'Webkit Moz O ms'.split(' '),
            startEvents = 'webkitAnimationStart animationstart oAnimationStart MSAnimationStart'.split(' '),
            pfx  = '';
        {
            var elm = document.createElement('fakeelement');
            if( elm.style.animationName !== undefined ) { animation = true; }   
             
            if( animation === false ) {
                for( var i = 0; i < domPrefixes.length; i++ ) {
                    if( elm.style[ domPrefixes[i] + 'AnimationName' ] !== undefined ) {
                        pfx = domPrefixes[ i ];
                        animationstring = pfx + 'Animation';
                        keyframeprefix = '-' + pfx.toLowerCase() + '-';
                        animationstartevent = startEvents[ i ];
                        animation = true;
                        break;
                    }
                }
            }
        }
         
        var animationName = 'resizeanim';
        var animationKeyframes = '@' + keyframeprefix + 'keyframes ' + animationName + ' { from { opacity: 0; } to { opacity: 0; } } ';
        var animationStyle = keyframeprefix + 'animation: 1ms ' + animationName + '; ';
    }
     
    function createStyles() {
        if (!stylesCreated) {
            //opacity:0 works around a chrome bug https://code.google.com/p/chromium/issues/detail?id=286360
            var css = (animationKeyframes ? animationKeyframes : '') +
                    '.resize-triggers { ' + (animationStyle ? animationStyle : '') + 'visibility: hidden; opacity: 0; } ' +
                    '.resize-triggers, .resize-triggers > div, .contract-trigger:before { content: \" \"; display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; } .resize-triggers > div { background: #eee; overflow: auto; } .contract-trigger:before { width: 200%; height: 200%; }',
                head = document.head || document.getElementsByTagName('head')[0],
                style = document.createElement('style');
             
            style.type = 'text/css';
            if (style.styleSheet) {
                style.styleSheet.cssText = css;
            } else {
                style.appendChild(document.createTextNode(css));
            }
 
            head.appendChild(style);
            stylesCreated = true;
        }
    }
     
    window.addResizeListener = function(element, fn){
        if (attachEvent) element.attachEvent('onresize', fn);
        else {
            if (!element.__resizeTriggers__) {
                if (getComputedStyle(element).position == 'static') element.style.position = 'relative';
                createStyles();
                element.__resizeLast__ = {};
                element.__resizeListeners__ = [];
                (element.__resizeTriggers__ = document.createElement('div')).className = 'resize-triggers';
                element.__resizeTriggers__.innerHTML = '<div class="expand-trigger"><div></div></div>' +
                                                                                        '<div class="contract-trigger"></div>';
                element.appendChild(element.__resizeTriggers__);
                resetTriggers(element);
                element.addEventListener('scroll', scrollListener, true);
                 
                /* Listen for a css animation to detect element display/re-attach */
                animationstartevent && element.__resizeTriggers__.addEventListener(animationstartevent, function(e) {
                    if(e.animationName == animationName)
                        resetTriggers(element);
                });
            }
            element.__resizeListeners__.push(fn);
        }
    };
     
    window.removeResizeListener = function(element, fn){
        if (attachEvent) element.detachEvent('onresize', fn);
        else {
            element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1);
            if (!element.__resizeListeners__.length) {
                    element.removeEventListener('scroll', scrollListener);
                    element.__resizeTriggers__ = !element.removeChild(element.__resizeTriggers__);
            }
        }
    }
})();

調用方法

addResizeListener(element,fun)    //element爲監聽的元素,fun爲當有變化時觸發的方法
 
//例如監聽body的高度變化:
addResizeListener(document.getElementsByTagName("body")[0],detectCallback);
var detectCallback = function() {
      console.log('頁面body高度發生了變化')
};

實例:

監聽iframe頁面變化時iframe的高度等於iframe裏面頁面body的高度

<iframe src="url" frameborder="0" id="container"></iframe>
 
 
//iframe 頁面代碼(注意,這裏指的的把代碼寫在iframe那個頁面的裏面,不是在iframe這個標籤的js下)
window.onload=function(){
    setParentIframeHeight('container');
    addResizeListener(document.getElementsByTagName("body")[0], detectCallback);
}
 
var detectCallback = function() {
  setParentIframeHeight('container');
};
 
function setParentIframeHeight(id){
    var parentIframe = parent.document.getElementById(id);
    parentIframe.height = document.body.scrollHeight;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章