摘要:一在講之前,先弄清屬性是默認值這是的值是是這是的值是因為是包括的,而只包括。可想而知,的中也包含了對的判斷。
一、在講之前,先弄清 boxSizing 屬性
(1)box-sizing 是默認值 "content-box"
這是divTwo
$().width()的值是 55
(2)box-sizing 是 "border-box"
這是divTwo
$().width()的值是 53
因為 border-box 是包括 border、padding、content 的,而 content-box 只包括 content。
可想而知,jQuery的$().width() 中也包含了對 borderBox 的判斷。
注意下div標簽的默認值
二、$().width()
作用:
獲取目標元素的寬度
源碼:
//源碼7033行 //$.each(obj,callback(index,item){}) jQuery.each( [ "height", "width" ], function( i, dimension ) { //i:0 dimension:height //i:1 dimension:width //cssHooks是用來定義style方法的 jQuery.cssHooks[ dimension ] = { //讀 //$().width() //參數:elem:目標DOM元素/computed:true/extra:"content" get: function( elem, computed, extra ) { console.log(elem, computed, extra,"extra7040") if ( computed ) { // 某些元素是有尺寸的信息的,如果我們隱式地顯示它們,前提是它必須有一個display值 // Certain elements can have dimension info if we invisibly show them // but it must have a current display style that would benefit // 上面這句話的意思是,某個元素用display:none,將它從頁面上去掉了,此時是獲取不到它的寬度的 // 如果要獲取它的寬度的話,需要隱式地顯示它們,比如display:absolute,visible:hidden // 然后再去獲取它的寬度 // block:false // none:true // rdisplayswap的作用是檢測 none和table開頭的 return rdisplayswap.test( jQuery.css( elem, "display" ) ) && // 兼容性的考慮,直接看 getWidthOrHeight // Support: Safari 8+ // Table columns in Safari have non-zero offsetWidth & zero // getBoundingClientRect().width unless display is changed. // Support: IE <=11 only // Running getBoundingClientRect on a disconnected node // in IE throws an error. // display為none的話,elem.getBoundingClientRect().width=0 // elem.getClientRects() 返回CSS邊框的集合 // https://developer.mozilla.org/zh-CN/docs/Web/API/Element/getClientRects ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? swap( elem, cssShow, function() { return getWidthOrHeight( elem, dimension, extra ); } ) : //$().width()情況 //dimension:width/extra:"content" getWidthOrHeight( elem, dimension, extra ); } }, }; } );
解析:
(1)box-sizing 是默認值,并且 display 不為 none
① rdisplayswap
作用:
檢測目標元素的display屬性的值 是否為none或以table開頭
// 檢測 display 的值是否為 none 或以 table 開頭 // Swappable if display is none or starts with table // 除了 "table", "table-cell", "table-caption" // except "table", "table-cell", or "table-caption" // display 的值,請訪問 https://developer.mozilla.org/en-US/docs/CSS/display // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display // 源碼6698行 var rdisplayswap = /^(none|table(?!-c[ea]).+)/,
如果display是none的話,就會調用swap()方法,反之,就直接調用getWidthOrHeight()方法
② getWidthOrHeight()
作用:
獲取width或height的值
//獲取 width 或 height //dimension:width/extra:"content" //源碼6823行 function getWidthOrHeight( elem, dimension, extra ) { // Start with computed style var styles = getStyles( elem ), val = curCSS( elem, dimension, styles ), //判斷 box-sizing 的值是否 是 border-box //如果啟用了 box-sizing,js 的 width 是會算上 margin、border、padding的 //如果不啟用的話,js 的 width 只會算 content //jQuery 的 width 自始至終都是算的 content isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box", valueIsBorderBox = isBorderBox; //火狐兼容性處理,可不看 // Support: Firefox <=54 // Return a confounding non-pixel value or feign ignorance, as appropriate. if ( rnumnonpx.test( val ) ) { if ( !extra ) { return val; } val = "auto"; } // 通過getComputedStyle檢查style屬性,并返回可靠的style屬性,這樣可以防止瀏覽器返回不可靠的值 // Check for style in case a browser which returns unreliable values // for getComputedStyle silently falls back to the reliable elem.style valueIsBorderBox = valueIsBorderBox && ( support.boxSizingReliable() || val === elem.style[ dimension ] ); console.log(valueIsBorderBox,"valueIsBorderBox6853") // Fall back to offsetWidth/offsetHeight when value is "auto" // This happens for inline elements with no explicit setting (gh-3571) // Support: Android <=4.1 - 4.3 only // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) if ( val === "auto" || !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) { val = elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ]; console.log(val,"val6862") // offsetWidth/offsetHeight provide border-box values valueIsBorderBox = true; } // Normalize "" and auto // 55px val = parseFloat( val ) || 0; console.log(val,extra,"val6869") // Adjust for the element"s box model return ( val + boxModelAdjustment( //DOM節點 elem, //width dimension, //content extra || ( isBorderBox ? "border" : "content" ), //true/false valueIsBorderBox, //styles styles, //55 // Provide the current computed size to request scroll gutter calculation (gh-3589) val ) ) + "px"; }
getWidthOrHeight() 里面有好多方法,我們一一來解析:
③ getStyles( elem )
作用:
獲取該 DOM 元素的所有 css 屬性的值
//獲取該DOM元素的所有css屬性的值 //源碼6501行 var getStyles = function( elem ) { // 兼容性處理,旨在拿到正確的view // Support: IE <=11 only, Firefox <=30 (#15098, #14150) // IE throws on elements created in popups // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" var view = elem.ownerDocument.defaultView; if ( !view || !view.opener ) { view = window; } //獲取所有CSS屬性的值 return view.getComputedStyle( elem ); };
可以看到,本質是調用了getComputedStyle()方法。
④ curCSS( elem, dimension, styles )
作用:
獲取元素的當前屬性的值
// 獲取元素的當前屬性的值 // elem, "position" // elem,width,styles // 源碼6609行 function curCSS( elem, name, computed ) { var width, minWidth, maxWidth, ret, // Support: Firefox 51+ // Retrieving style before computed somehow // fixes an issue with getting wrong values // on detached elements style = elem.style; //獲取elem所有的樣式屬性 computed = computed || getStyles( elem ); // console.log(computed,"computed6621") // getPropertyValue is needed for: // .css("filter") (IE 9 only, #12537) // .css("--customProperty) (#3144) if ( computed ) { //返回元素的屬性的當前值 //position:static //top:0px //left:0px ret = computed.getPropertyValue( name ) || computed[ name ]; console.log(ret,"ret6627") //如果目標屬性值為空并且目標元素不在目標元素所在的文檔內(感覺這種情況好奇怪) if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { //使用jQuery.style方法來獲取目標元素的屬性值 ret = jQuery.style( elem, name ); } // A tribute to the "awesome hack by Dean Edwards" // Android Browser returns percentage for some values, // but width seems to be reliably pixels. // This is against the CSSOM draft spec: // https://drafts.csswg.org/cssom/#resolved-values //當屬性設置成數值時,安卓瀏覽器會返回一些百分比,但是寬度是像素顯示的 //這違反了CSSOM草案規范 //所以以下方法是修復不規范的width屬性的 if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { // Remember the original values width = style.width; minWidth = style.minWidth; maxWidth = style.maxWidth; // Put in the new values to get a computed value out style.minWidth = style.maxWidth = style.width = ret; ret = computed.width; // Revert the changed values style.width = width; style.minWidth = minWidth; style.maxWidth = maxWidth; } } return ret !== undefined ? // 兼容性,IE下返回的zIndex的值是數字, // 而使用jQuery獲取的屬性都是返回字符串 // Support: IE <=9 - 11 only // IE returns zIndex value as an integer. ret + "" : ret; }
可以看到,curCSS本質是調用了computed.getPropertyValue( name )方法,也就是說我們可以這樣去獲取目標元素的屬性值:
let a=document.getElementById("pTwo") a.ownerDocument.defaultView.getComputedStyle(a).getPropertyValue("width") //55px
目標元素的所屬 view,調用getComputedStyle()方法,獲取目標元素的所有 CSS 屬性,再調用getPropertyValue("width"),獲取目標width的屬性值,為 55px
注意:無論box-sizing的值是border-box還是content-box,上面的方法獲取的width值都是55px,這是不符合 CSS3 盒子模型的,所以 jQuery 拿到該值后,還會繼續處理。
⑤ boxModelAdjustment
因為這里討論的是情況一,所以boxModelAdjustment()會直接返回 0
綜上:當box-sizing 是默認值,并且 display 不為 none時,返回的width是:
parseFloat(a.ownerDocument.defaultView.getComputedStyle(a).getPropertyValue("width")) //55
(2)box-sizing 值為 border-box
這是divTwo
$("#pTwo").width() //51 document.getElementById("pTwo").style.width //55px
可以看到,原生 js 獲取 width 是不遵循 CSS3 盒子規范的。
borderBox 的判斷在getWidthOrHeight()方法中,直接看過去:
//獲取 width 或 height //dimension:width/extra:"content" //源碼6823行 function getWidthOrHeight( elem, dimension, extra ) { xxx ... var styles = getStyles( elem ), //true isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box", //true valueIsBorderBox = isBorderBox; xxx ... valueIsBorderBox = valueIsBorderBox && //val值是通過a.ownerDocument.defaultView.getComputedStyle(a).getPropertyValue("width")得出的 //但又通過js原生的style.width來取值并與val相比較 ( support.boxSizingReliable() || val === elem.style[ dimension ] ); console.log(val === elem.style[ dimension ],"valueIsBorderBox6853") // 55 val = parseFloat( val ) || 0; // Adjust for the element"s box model return ( val + //borderBox走這里 boxModelAdjustment( //DOM節點 elem, //width dimension, //content extra || ( isBorderBox ? "border" : "content" ), //true/false valueIsBorderBox, //styles styles, //55 // Provide the current computed size to request scroll gutter calculation (gh-3589) val ) ) + "px"; }
boxModelAdjustment():
作用:
集中處理borderBox的情況
//參數說明: //elem:DOM節點/dimension:width/box:content/isBorderBox:true/false/styles:styles/computedVal:55 //源碼6758行 function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { var i = dimension === "width" ? 1 : 0, extra = 0, delta = 0; // 如果 boxSizing 的屬性值,而不是 borderBox 的話,就直接返回 0 // Adjustment may not be necessary if ( box === ( isBorderBox ? "border" : "content" ) ) { console.log("content1111","content6768") return 0; } //小技巧 //i 的初始值是 0/1 //然后 cssExpand = [ "Top", "Right", "Bottom", "Left" ] for ( ; i < 4; i += 2 ) { // Both box models exclude margin if ( box === "margin" ) { //var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; //width 的話,就是 marginRight/marginLeft //height 的話,就是 marginTop/marginBottom //jQuery.css( elem, box + cssExpand[ i ], true, styles ) 的意思就是 //返回 marginRight/marginLeft/marginTop/marginBottom 的數字,并給 delta 加上 delta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); } // If we get here with a content-box, we"re seeking "padding" or "border" or "margin" // 如果不是 borderBox 的話 if ( !isBorderBox ) { // Add padding // 添加 padding-xxx delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); // For "border" or "margin", add border if ( box !== "padding" ) { delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); // But still keep track of it otherwise } else { extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); } // If we get here with a border-box (content + padding + border), we"re seeking "content" or // "padding" or "margin" } else { // 去掉 padding // For "content", subtract padding if ( box === "content" ) { //width,去掉paddingLeft,paddingRight的值 delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); } // For "content" or "padding", subtract border // 去掉 borderXXXWidth if ( box !== "margin" ) { //width,去掉borderLeftWidth,borderRightWidth的值 delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); } } } // Account for positive content-box scroll gutter when requested by providing computedVal if ( !isBorderBox && computedVal >= 0 ) { // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border // Assuming integer scroll gutter, subtract the rest and round down delta += Math.max( 0, Math.ceil( //就是將dimension的首字母做個大寫 elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - computedVal - delta - extra - 0.5 ) ); } return delta; }
可以看到,isBorderBox 為 true 的話,會執行下面兩段代碼:
if ( box === "content" ) { //width,去掉paddingLeft,paddingRight的值 delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); }
if ( box !== "margin" ) { //width,去掉borderLeftWidth,borderRightWidth的值 delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); }
去除了paddingLeft、paddingRight、borderLeftWidth和borderRightWidth,并最終返回值
二、$().width(xxx)
作用:
設置目標元素的寬度
源碼:
//源碼7033行 //$.each(obj,callback(index,item){}) jQuery.each( [ "height", "width" ], function( i, dimension ) { //i:0 dimension:height //i:1 dimension:width //cssHooks是用來定義style方法的 jQuery.cssHooks[ dimension ] = { //寫 //$().width(55) //elem:DOM節點,value:55,extra:content set: function( elem, value, extra ) { var matches, styles = getStyles( elem ), isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box", //-4 subtract = extra && boxModelAdjustment( elem, dimension, extra, isBorderBox, styles ); // 如果是 borderBox 的話,通過 offset 計算的尺寸是不準的, // 所以要假設成 content-box 來獲取 border 和 padding // Account for unreliable border-box dimensions by comparing offset* to computed and // faking a content-box to get border and padding (gh-3699) //true true "static" //調整 subtract if ( isBorderBox && support.scrollboxSize() === styles.position ) { subtract -= Math.ceil( elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - parseFloat( styles[ dimension ] ) - boxModelAdjustment( elem, dimension, "border", false, styles ) - 0.5 ); console.log(subtract,"subtract7169") } // 如果需要進行值調整,則轉換為像素 // Convert to pixels if value adjustment is needed //如果是 borderBox 并且 value 的單位不是 px,則會轉換成像素 if ( subtract && ( matches = rcssNum.exec( value ) ) && ( matches[ 3 ] || "px" ) !== "px" ) { elem.style[ dimension ] = value; value = jQuery.css( elem, dimension ); } //59px return setPositiveNumber( elem, value, subtract ); } }; } );
解析:
(1)整體上看,實際上兩個 if ,最后再 return 一個setPositiveNumber()方法
(2)注意subtract ,如果有 borderBox 屬性,并且 borderWidth、padding 有值的話,subtract 一般為負數,比如下面的例子,subtract = -4
$("#pTwo").width(55)
反之則會是 0
(3)兩個 if 我試了下,都會去執行,所以直接看的setPositiveNumber ()
setPositiveNumber:
作用:
設置真正的 width 值
function setPositiveNumber( elem, value, subtract ) { // 標準化相對值 // Any relative (+/-) values have already been // normalized at this point //[ // "55px", // undefined, // "55", // "px", // index: 0, // input: "55px", // groups: undefined, // index: 0 // input: "55px" // ] var matches = rcssNum.exec( value ); console.log(matches,( subtract || 0 ),"matches6760") return matches ? //(0,55-(-4))+"px" //Math.max(a,b) 返回兩個指定的數中帶有較大的值的那個數 // Guard against undefined "subtract", e.g., when used as in cssHooks Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : value; }
如果是 borderBox,width 會設置成 59px(雖然表面上開發者設置的是$("#pTwo").width(55)),反之,則是 55px
總結:
1、$().width()
(1)不是borderBox
$().width()=parseFloat(elem.ownerDocument.defaultView.getComputedStyle(elem).getPropertyValue("width"))
(2)是borderBox()
在(1)的基礎上執行boxModelAdjustment()方法,去除 borderWidth、padding
2、$().width(xxx)
(1)不是borderBox
width=xxx
(2)是borderBox
width=xxx+ setPositiveNumber()
(完)
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/109480.html
摘要:根據的間隔,利用循環執行,從而達到渲染動畫的目的。最后,附上的流程圖,建議配合整個的流程圖二的最后一個圖一起看下篇將會模擬實現方法,敬請期待完 三、doAnimation內部的Animation()方法作用:$().animate()核心方法 源碼: //animate()核心方法 //源碼7844行 //elem:目標元素 //this:目標元素 //{widt...
摘要:前言需要先看源碼解析之和一舉例的寬度先變成,再變成,最后變成這是在異步調用中,進行同步調用動畫是異步的就是連續調用二作用通過樣式將元素從一個狀態改變為另一個狀態源碼之前有說過是的方法源碼行是否是空對象,方法執行單個動畫的封裝的本質是執行 showImg(https://segmentfault.com/img/remote/1460000019594521); 前言:需要先看 jQue...
閱讀 3518·2021-11-15 11:38
閱讀 838·2021-11-08 13:27
閱讀 2251·2021-07-29 14:50
閱讀 2979·2019-08-29 13:06
閱讀 849·2019-08-29 11:22
閱讀 2421·2019-08-29 11:04
閱讀 3512·2019-08-28 18:23
閱讀 897·2019-08-26 13:46