slideDown,slideUp是页面中很常见的交互效果,一个元素会先以display:none的方式隐藏起来,等到触发的时候,再以以某种缓动动画展开到一定高度,那么如何获取到隐藏元素的高度?

考虑两种情况,第一,元素本身设置了隐藏可以用display === 'none'判断,情况二,元素的父级设置了隐藏,但本身还是diplay:block,可以用getComputedStyle获取元素的宽高来判断。

	var rect = ele.getBoundingClientRect();
   return rect.width === 0 && rect.height === 0;

思路

对于情况一,将元素display:block,visibility:hidden同时为了不影响其他的元素,还要设置绝对定位,计算完成以后,将元素的样式还原。 情况二,比较麻烦,向上查找父元素,然后设置父元素可见,再计算元素高度,未免显得繁琐,考虑使用cloneNode将元素插入到body中,然后计算高度

实现

首先获取元素的关键样式

	function getStyle (ele) {
		var styles = window.getComputedStyle(ele);
		return {
			display: styles.display,
			position: styles.position,
			visibility: styles.visibility,
			height: styles.height
		}
	}

获取正常显示情况下的样式

	
	ele.style.display = 'block';
	ele.style.position = 'absolute';
	ele.style. visibility = 'hidden';
	var actualHeight = ele.offsetHeight;

如果父级隐藏,则克隆节点


	var cloned = ele. p.cloneNode(true);
	document.body.appendChild(cloned);
	

代码

	
	function getActualHeight (ele) {
		function getStyle (e) {
			var styles = window.getComputedStyle(e);
			return {
				display: styles.display,
				position: styles.position,
				visibility: styles.visibility,
				height: styles.height
			}
		}
		
		function isIntangible (e) {
			var rect = e.getBoundingClientRect();
   			return rect.width === 0 && rect.height === 0;
		}
		
		function cloneEle(e) {
			var cloned = e.cloneNode(true);
			document.body.appendChild(cloned);
			return cloned;
		} 
		
		function getNormaledHeight (e) {
			e.style.display = 'block';
			e.style.position = 'absolute';
			e.style. visibility = 'hidden';
			return e.offsetHeight;
		}
		
		function resetStyle (e, origin) {
			for (key in origin) {
				e.style[key] = origin[key];
			}
		}
		
		var originalStyle = getStyle(ele),
			 dataH,
			 actualHeight;
		
		if ( datah = ele.getAttribute('data-height')) {
            return datah;
       }
		if (originalStyle.display !== 'none' && (!isIntangible(ele))) {
			 actualHeight = getNormaledHeight(ele);
           resetStyle(ele, originalStyle);
           ele.setAttribute('data-height', actualHeight);
			return originalStyle.height;
		}
		else if (originalStyle.display === 'none') {
			var e = cloneEle(ele);
	       actualHeight = getNormaledHeight(e);
	       document.body.removeChild(e);
	       ele.setAttribute('data-height', actualHeight);
	       return actualHeight
	    }
	}

写完再看,可以完全用克隆节点来解决,但是有一个弊端,如果设置节点样式的时候,选择器中包含着父级节点,那么这个节点克隆出来以后必然会,丢失一些样式,所以这个方法适用于独立化的css组件。

	function getActualHeight (ele) {
		
		function cloneEle(e) {
			var cloned = e.cloneNode(true);
			document.body.appendChild(cloned);
			return cloned;
		} 
		
		function getNormaledHeight (e) {
			e.style.display = 'block';
			e.style.position = 'absolute';
			e.style. visibility = 'hidden';
			return e.offsetHeight;
		}
		
		var n = cloneEle(ele);
		var h = getNormaledHeight(n);
		document.body.removeChild(n);
		return h;
	}