前言
最近几天忙着找实习的事情,然后就没有更新啦>0<,然后今天要开始继续学习啦。
原生JavaScript里面有几个系列来获取元素的尺寸。原生属性
偏移量系列
- offsetWidth
- offsetHeight
- offsetLeft
- offsetTop
- offsetParent:距离元素最近的定位(relative、absolute)祖先元素,可递归上溯。
offsetWidth/offsetHeight = 元素内容 + padding + border。
客户区系列
- clientWidth
- clientHeight
用于描述元素的内尺寸:元素内容+两边内边距
滚动大小
- scrollWidth
- scrollHeight
- scrollLeft
- scrollTop
scrollWidth/scrollHeight:元素内容的总高度或宽度。
scrollTop/scrollLeft:元素滚动条位置。在浏览器中的区别在于: IE6、IE7认为scrollHeight是网页内容实际高度,可以小于clientHeight。FF、Chrome 认为scrollHeight是网页内容高度,不过最小值是clientHeight。 浏览器窗口的滚动条位置:window对象的 pageXoffset 和 pageYoffset , IE8及更早版本可以通过scrollLeft和scrollTop属性获得滚动条位置。
一些细节
document.documentElement与document.body
document.body是DOM中Document对象里的body节点。 document.documentElement是文档对象根节点(html)的引用。
IE 在怪异模型下document.documentElement无法正确取到clietHeight、scrollHeight等值,比如clietHeight=0。可以见IE的怪异模型并没有把html作为盒子模型的一部分。
$(window).width() 代表了当前浏览器可见区域的宽度
$(document).width() 则代表了整个文档的宽度,可以有滚动内容1 元素的宽素可以是内联或者通过link定义,所以通过style是不可取的
2 元素在隐藏状态下是不能获取任何尺寸的 display:none3 CSS3引入了box-sizing的设置jQuery.css(elem, type, extra)/^(none|table(?!-c[ea]).+)/test(jQuery.css(elem, "display")) //
。jQuery就会对元素增加position: absolute; visibility: hidden;
function getStyles(elem) { return elem.ownerDocument.defaultView.getComputedStyle(elem, null);};
这里defaultView在浏览器中返回的是Document的Window对象。
window.getComputedStyle("元素", "伪类")返回当前元素的所有样式。它只能获取样式,是只读的,并且它获得的是元素最终的样式,不仅仅是style属性里写的。然后为什么用defaultView,其实是差不多的,可以看大佬的博客谈到的:另外IE还有一个element.currentStyle,也是元素最终的样式。//交换元素样式(获取到display为none的宽度)function swap(elem, options, callback, args) { var ret, name, old = {}; //遍历options的属性,付给传入元素,并且保存原来元素对应的属性 for (name in options) { old[name] = elem.style[name]; elem.style[name] = options[name]; } //下面的代码是相当于执行了getWidthOrHeight函数获取到了宽度 ret = callback.apply(elem, args || []); //再复原元素 for (name in options) { elem.style[name] = old[name]; } return ret;};//获取当前样式function curCSS(elem,name) { var computed = getStyles(elem); var ret = computed.getPropertyValue(name) || computed[name]; return ret;}
getPropertyValue()在上面大佬的文章里也有提到过,就是获取属性值的。在IE中则使用getAttribute方法,但是它在拿style属性值的时候,前者可以不用驼峰式写法,后者则必须。
//获取宽高function getWidthOrHeight( elem, name, extra ) { val = name === "width" ? elem.offsetWidth : elem.offsetHeight, styles = getStyles( elem ), //borderBox情况 isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; // IE11全屏的时候在iframe里的元素会缩小100辈 // In IE 11 fullscreen elements inside of an iframe have // 100x too small dimensions (gh-1764). if ( document.msFullscreenElement && window.top !== window ) { if ( elem.getClientRects().length ) { val = Math.round( elem.getBoundingClientRect()[ name ] * 100 ); } } // 一些没有设置HTML属性的元素获取offsetWidth会返回undefined if ( val <= 0 || val == null ) { //获取元素样式的值 val = curCSS( elem, name, styles ); if ( val < 0 || val == null ) { val = elem.style[ name ]; } // 计算单位不是px,所以直接返回 if ( rnumnonpx.test( val ) ) { return val; } valueIsBorderBox = isBorderBox && ( support.boxSizingReliable() || val === elem.style[ name ] ); // 以防出现""和"auto"值 val = parseFloat( val ) || 0; } return ( val + augmentWidthOrHeight( elem, name, extra || ( isBorderBox ? "border" : "content" ), valueIsBorderBox, styles ) ) + "px";}
计算display为none的元素的宽度
var cssShow = { display: "block", position: "absolute", visibility: "hidden"}$('#test2').click(function(){ var elem = div; function width() { if( /^(none|table(?!-c[ea]).+)/.test(curCSS(div, 'display')) ){ return swap(elem, cssShow, function() { return getWidthOrHeight(elem, 'width', 'content'); }) } } show('模拟jQuery.width的处理: '+ width())})
偏移算法
innerWidth、innerHeight
用于获得匹配集合中第一个元素的当前计算的内部宽高(包括padding,但不包括border),或 设置每一个匹配元素的内部宽高。outerWidth、outerHeight
获取元素集合中第一个元素的当前计算宽高度值,包括padding,border和选择性的margin。var cssExpand = ["Top", "Right", "Bottom", "Left"];/*** 额外处理高度/宽度* elem:目标元素* name:目标测量(width/height)* extra:包括的最外层内容* isBorderBox:是怪异模式盒子吗* styles:样式*/function augmentWidthOrHeight(elem, name, extra, isBorderBox, styles) { var i = extra === (isBorderBox ? "border" : "content") ? // 如果isBorderBox有值,则直接i=4,跳过下面的循环,就避免额外的步骤 4 : // 否则初始化垂直水平的属性,如果是width,name就是1,否则就是0 name === "width" ? 1 : 0, val = 0; /* * width:如果i=1,则循环只会加上right和left * height:如果i=0,则循环只会加上top和bottom */ for (; i < 4; i += 2) { // 如果extra是margin就把margin都加上 if (extra === "margin") { val += jQuery.css(elem, extra + cssExpand[i], true, styles); } // 如果是怪异模型 if (isBorderBox) { //width包含了padding,所以如果exrta是content的话要去除padding if (extra === "content") { val -= jQuery.css(elem, "padding" + cssExpand[i], true, styles); } //如果extra不是margin的话,还要减去2边的宽度 if (extra !== "margin") { val -= jQuery.css(elem, "border" + cssExpand[i] + "Width", true, styles); } } else { //因为不是怪异模型,所以直接再加上padding val += jQuery.css(elem, "padding" + cssExpand[i], true, styles); // extra不可能是padding了(上面加过了),所以再加上border if (extra !== "padding") { val += jQuery.css(elem, "border" + cssExpand[i] + "Width", true, styles); } } } return val;}
首先获取基本的offsetWidth和offsetHeight,要得到下面几个值,再加上这个函数的结果即可。
innerWidth:augmentWidthOrHeight(elem, 'width', "padding", true, styles)innerHeight:augmentWidthOrHeight(elem, 'height', "padding", true, styles)outerWidth:augmentWidthOrHeight(elem, 'width', "border", true, styles)outerHeight:augmentWidthOrHeight(elem, 'height', "border", true, styles)