1. 程式人生 > >js監聽某個元素高度變化來改變父級iframe的高度

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

key ava target splice call string case 改變 實例

最近需要做一個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

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