jQuery2.0.3源碼分析系列(28) 元素大小

最近的分析都是有點不溫不火,基本都是基礎的回顧了css

今年博客的目標目前總的來講有2大塊html

JS版的設計模式,會用jQuery來詮釋node

JS版的數據結構,最近也一直在狠狠的學習中.jquery

 

HTML息息相關的的樣式web

偏移量

offsetWidth offsetHeight offsetLeft offsetTopchrome

image

offsetHeight/offsetWidth: 表述元素的外尺寸:元素內容+內邊距+邊框(不包括外邊距)設計模式

offsetLeft/offsetTop: 表示該元素的左上角(邊框外邊緣)與已定位的父容器(offsetParent對象)左上角的距離。瀏覽器

offsetParent元素是指元素最近的定位(relative,absolute)祖先元素,可遞歸上溯。數據結構

 

 


客戶區大小

clientWidth clientHeight ide

image

clientWidth/clientHeight: 用於描述元素的內尺寸:元素內容+兩邊內邊距

 

 


滾動大小

scrollWidth scrollHeight scrollLeft scrollTop

image

scrollHeight/scrollWidth: 元素內容的總高度或寬度

scrollLeft/scrollTop:是指元素滾動條位置,它們是可寫的(被隱藏的內容區域左側/上方的像素)

瀏覽器窗口的滾動條位置:window對象的pageXoffset和pageYoffset, IE 8及更早版本能夠經過scrollLeft和scrollTop屬性得到滾動條位置

 


如下是網上的總結,我收集下

Chrome/FF/Safari/opera
對這些瀏覽器而言,window有個屬性innerWidth/innerHeight包含的是整個文檔的可視區域尺寸,注意,這個尺寸是包含滾動條大小的。
若是咱們不計滾動條的影響,就能夠直接使用這兩個屬性。
若是滾動條會影響(好比最大化彈出框),那麼應該想另外的辦法。

 

document.documentElementy與document.body

Document對象是每一個DOM樹的根,可是它並不表明樹中的一個HTML元素,document.documentElement屬性引用了做爲文檔根元素的html標記,document.body屬性引用了body標記
咱們這裏獲取常見的三個值(scrollWidth、offsetWidth和clientwidth)來比較一下

document.documentElement.scrollWidth返回整個文檔的寬度
document.documentElement.offsetWidth返回整個文檔的可見寬度
document.documentElement.clientwidth返回整個文檔的可見寬度(不包含邊框),clientwidth = offsetWidth - borderWidth

不過通常來講,咱們不會給document.documentElement來設置邊框,因此這裏的clientwidth 與 offsetWidth一致

 

document.body.scrollWidth返回body的寬度
注意,這裏的scrollWidth有個不一致的地方,基於webkit的瀏覽器(chrome和safari)返回的是整個文檔的寬度,也就是和document.documentElement.scrollWidth一致,
opera和FF返回的就是標準的body 的scrollWidth,我的以爲opera和FF算是比較合理的。


document.body.offsetWidth返回body的offsetWidth
document.body.clientwidth返回body的clientwidth(不包含邊框),clientwidth = offsetWidth - borderWidth

咱們看上面的例子,會發現

body和documentElement的有些值是相等的,這並非表示他們是等同的。而是由於當咱們沒有給body設置寬度的時候,document.body默認佔滿整個窗口寬度,

因而就有:

document.body.scrollWidth = document.documentElement.scrollWidth
document.body.offsetWidth = document.documentElement.offsetWidth
document.body.clientwidth = document.documentElement.clientwidth - document.body.borderWidth(body的邊框寬度)


當咱們給body設置了一個寬度的時候,區別就出來了。

 

IE9/IE8
這兩個差很少,惟一的區別是IE9包含window.innerWidth屬性,而IE8不包含window.innerWidth屬性。
document.documentElement.scrollWidth返回整個文檔的寬度,和FF等瀏覽器一致
document.documentElement.offsetWidth返回整個文檔的可見寬度(包含滾動條,值和innerWidth一致),注意,這裏和FF等瀏覽器又有點區別。
document.documentElement.clientwidth返回整個文檔的可見寬度(不包含邊框),和FF等瀏覽器一致。clientwidth = offsetWidth - 滾動條寬度

document.body.scrollWidth返回body的寬度,注意,這裏的scrollWidth和FF等瀏覽器有點區別,這裏並不包括body自己的border寬度。
所以例子中,相比FF少了10px。
document.body.offsetWidth返回body的offsetWidth,和FF等瀏覽器一致
document.body.clientwidth返回body的clientwidth(不包含邊框),和FF等瀏覽器一致,clientwidth = offsetWidth – borderWidth

 

IE7與IE9/IE8的主要區別是
第1、document.documentElement.offsetWidth的返回值不同,
參見上面說的,IE9/IE8的document.documentElement.offsetWidth包含滾動條,可是,IE7的document.documentElement.offsetWidth不包含滾動條。
第2、document.documentElement.scrollWidth返回整個文檔的寬度,注意,這裏和IE9/IE八、FF等瀏覽器又有不一致,對於IE9/IE八、FF等瀏覽器,scrollWidth最小不會小於窗口的寬度,可是在IE下沒有這個限制,文檔有多小,這個就有多小
其餘卻是挺一致的。

 

IE6了
IE6的document.documentElement返回值與IE9/IE8沒有區別(因而可知,對於document.documentElement,IE7就是個奇葩)。
話說回來,IE的document.body就是個奇葩,當沒有給body設置寬度的時候,body是默認佔滿整個文檔的(注意,其餘的瀏覽器都是佔滿整個窗口),固然,最小值是整個窗口的大小,就是說body指向了根元素。
所以,在算上IE6在解析width方面的bug,和其餘的瀏覽器的區別就淋漓盡致了。
document.body.scrollWidth返回body的寬度,和IE9/IE8/IE7一致
document.body.offsetWidth返回body的offsetWidth,注意,因爲body的不一樣,這裏的offsetWidth = scrollWidth + borderWidth
document.body.clientwidth返回body的clientwidth(不包含邊框)clientwidth = offsetWidth - borderWidth
另外,有一點和IE7一樣,就是document.documentElement.scrollWidth沒有最小寬度限制。

 

 


源碼解析

先看jQuery對窗口大小六種類似方法的生成

 

jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
        jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
      
//執行代碼
        });
    });

擴展方法仍是用的合併的模式,把具備相同特性的方法採用合併處理

循環生成是藝術,須要深入瞭解它們的功能與共同點,而後將特異點組成一個對象,好處天然是省代碼了,而後能夠集中處理

 

執行代碼

例如:.width()

爲匹配的元素集合中獲取第一個元素的當前計算寬度值。

return jQuery.access( this, function( elem, type, value ) {
    var doc;
    if ( jQuery.isWindow( elem ) ) {
        return elem.document.documentElement[ "client" + name ];
    }

    // Get document width or height
    if ( elem.nodeType === 9 ) {
        doc = elem.documentElement;
        return Math.max(
            elem.body[ "scroll" + name ], doc[ "scroll" + name ],
            elem.body[ "offset" + name ], doc[ "offset" + name ],
            doc[ "client" + name ]
        );
    }

    return value === undefined ?
        jQuery.css( elem, type, extra ) :
        jQuery.style( elem, type, value, extra );
}, type, chainable ? margin : undefined, chainable, null );

 

A.首先先解釋下普通元素和非普通元素,

非普通元素是指window,document這些 元素對象,

普通元素是指除window,document以外的元素,如:div

 

B.css(width) 和 .width()之間的區別?

  • 對於非普通元素,只能使用 .width()

  • 對於普通的元素 ,他們的做用相同

  • 後者返回一個沒有單位的數值(例如,400),前者是返回帶有完整單位的字符串(例如,400px)。當一個元素的寬度須要數學計算的時候推薦使用.width() 方法

     

    C.非普通元素的獲取

    如:window

    $(window).width();   //瀏覽器窗口
    即返回HTML的窗口,因此代碼就是document.documentElement[「clientWidth」]
    if ( jQuery.isWindow( elem ) ) {
            return elem.document.documentElement[ "client" + name ];
        }
     
    document
    $(document).width();   //HTML文檔窗口

    取最大值,由於能夠帶卷滾條溢出

    if ( elem.nodeType === 9 ) {
        doc = elem.documentElement;
    
        // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],
        // whichever is greatest
        return Math.max(
            elem.body[ "scroll" + name ], doc[ "scroll" + name ],
            elem.body[ "offset" + name ], doc[ "offset" + name ],
            doc[ "client" + name ]
        );
    }
     

    D.普通元素取值

    jQuery.cssHooks

    由於有些樣式不是簡單的讀寫屬性就能夠的,好比width就不是簡單地讀取el.style.width。爲了解決這個問題,jquery定義了一個屬性 $.cssHooks,這裏能夠自定義對某個屬性的get和set操做。並且jquery中就是用cssHooks來處理某些特殊屬性的

    對CSS的操做都是經過統一的API調用,操做的屬性是

    1. borderWidth: Object
    2. height: Object
    3. margin: Object
    4. opacity: Object
    5. padding: Object
    6. width: Object

    此時就會用jQuery.cssHooks方法處理兼容問題,

     

    width,height的鉤子方法

    jQuery.each([ "height", "width" ], function( i, name ) {
            jQuery.cssHooks[ name ] = {
                get: function( elem, computed, extra ) {
                    if ( computed ) {
                        return elem.offsetWidth === 0 && rdisplayswap.test( jQuery.css( elem, "display" ) ) ?
                            jQuery.swap( elem, cssShow, function() {
                                return getWidthOrHeight( elem, name, extra );
                            }) :
                            getWidthOrHeight( elem, name, extra );
                    }
                },
    
                set: function( elem, value, extra ) {
                    var styles = extra && getStyles( elem );
                    return setPositiveNumber( elem, value, extra ?
                        augmentWidthOrHeight(
                            elem,
                            name,
                            extra,
                            jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
                            styles
                        ) : 0
                    );
                }
            };

    get 方法:

    1 節點隱藏等狀況下,height、width等獲取值不許,此時需利用jQuery.swap方法來得到準確值

    2 getWidthOrHeight獲取準確值

     

    本章大致回顧下了跟HTML相關處理的10種方法與jQuery中相對應的處理流,下章再具體分析jQuery中對應每種不一樣兼容的處理

相關文章
相關標籤/搜索