【笔记】jQuery源码(宽度&高度)

前言

最近几天忙着找实习的事情,然后就没有更新啦>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)

    原文作者:MOCHIKO
    原文地址: https://segmentfault.com/a/1190000014201204
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞