jQuery2.0.3原始碼分析系列(28) 元素大小
最近的分析都是有點不溫不火,基本都是基礎的回顧了
今年部落格的目標目前總的來說有2大塊
JS版的設計模式,會用jQuery來詮釋
JS版的資料結構,最近也一直在狠狠的學習中.
HTML息息相關的的樣式
偏移量
offsetWidth offsetHeight offsetLeft offsetTop
offsetHeight/offsetWidth: 表述元素的外尺寸:元素內容+內邊距+邊框(不包括外邊距)
offsetLeft/offsetTop: 表示該元素的左上角(邊框外邊緣)與已定位的父容器(offsetParent物件)左上角的距離。
offsetParent元素是指元素最近的定位(relative,absolute)祖先元素,可遞迴上溯。
客戶區大小
clientWidth clientHeight
clientWidth/clientHeight: 用於描述元素的內尺寸:元素內容+兩邊內邊距
滾動大小
scrollWidth scrollHeight scrollLeft scrollTop
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呼叫,操作的屬性是
- borderWidth: Object
- height: Object
- margin: Object
- opacity: Object
- padding: Object
- 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中對應每種不同相容的處理
如果您看完本篇文章感覺不錯,請點選一下右下角的【推薦】來支援一下博主,謝謝!
如果是原創文章,轉載請註明出處!!!