国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

jQuery源碼解析之width()

ARGUS / 896人閱讀

摘要:一在講之前,先弄清屬性是默認值這是的值是是這是的值是因為是包括的,而只包括。可想而知,的中也包含了對的判斷。

一、在講之前,先弄清 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]).+)/,

如果displaynone的話,就會調用swap()方法,反之,就直接調用getWidthOrHeight()方法

getWidthOrHeight()
作用:
獲取widthheight的值

 //獲取 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 );
}

去除了paddingLeftpaddingRightborderLeftWidthborderRightWidth,并最終返回值

二、$().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

這是divTwo
$("#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

相關文章

  • jQuery源碼解析$().animate()(下)

    摘要:根據的間隔,利用循環執行,從而達到渲染動畫的目的。最后,附上的流程圖,建議配合整個的流程圖二的最后一個圖一起看下篇將會模擬實現方法,敬請期待完 三、doAnimation內部的Animation()方法作用:$().animate()核心方法 源碼: //animate()核心方法 //源碼7844行 //elem:目標元素 //this:目標元素 //{widt...

    raledong 評論0 收藏0
  • jQuery源碼解析$().animate()(上)

    摘要:前言需要先看源碼解析之和一舉例的寬度先變成,再變成,最后變成這是在異步調用中,進行同步調用動畫是異步的就是連續調用二作用通過樣式將元素從一個狀態改變為另一個狀態源碼之前有說過是的方法源碼行是否是空對象,方法執行單個動畫的封裝的本質是執行 showImg(https://segmentfault.com/img/remote/1460000019594521); 前言:需要先看 jQue...

    Batkid 評論0 收藏0

發表評論

0條評論

ARGUS

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<