前言
最近几天忙着找实习的事情,然后就没有更新啦>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:none
3 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,其实是差不多的,可以看大佬的博客谈到的:
http://www.zhangxinxu.com/wor…
另外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)