最近需要做一個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 頁面代碼 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; }
detect-element-resize.js插件地址:https://github.com/sdecima/javascript-detect-element-resize