1. 程式人生 > >jQuery2.0.3原始碼分析系列(28) 元素大小

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

章節導航

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

今年部落格的目標目前總的來說有2大塊

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

JS版的資料結構,最近也一直在狠狠的學習中.

HTML息息相關的的樣式

偏移量

offsetWidth offsetHeight offsetLeft offsetTop

image

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

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

offsetParent元素是指元素最近的定位(relative,absolute)祖先元素,可遞迴上溯。

客戶區大小

clientWidth clientHeight 

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的主要區別是  第一、document.documentElement.offsetWidth的返回值不一樣,  參見上面說的,IE9/IE8的document.documentElement.offsetWidth包含滾動條,但是,IE7的document.documentElement.offsetWidth不包含滾動條。  第二、document.documentElement.scrollWidth返回整個文件的寬度,注意,這裡和IE9/IE8、FF等瀏覽器又有不一致,對於IE9/IE8、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中對應每種不同相容的處理

如果您看完本篇文章感覺不錯,請點選一下右下角的推薦來支援一下博主,謝謝!

如果是原創文章,轉載請註明出處!!!