var curCSS, iframe, // swappable if display is none or starts with table except "table", "table-cell", or "table-caption" // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display rdisplayswap = /^(none|table(?!-c[ea]).+)/, rmargin = /^margin/, rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ), rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ), rrelNum = new RegExp( "^([+-])=(" + core_pnum + ")", "i" ), elemdisplay = { BODY: "block" }, cssShow = { position: "absolute", visibility: "hidden", display: "block" }, cssNormalTransform = { letterSpacing: 0, fontWeight: 400 }, cssExpand = [ "Top", "Right", "Bottom", "Left" ], cssPrefixes = [ "Webkit", "O", "Moz", "ms" ]; // return a css property mapped to a potentially vendor prefixed property function vendorPropName( style, name ) { // shortcut for names that are not vendor prefixed if ( name in style ) { return name; } // check for vendor prefixed names var capName = name.charAt(0).toUpperCase() + name.slice(1), origName = name, i = cssPrefixes.length; while ( i-- ) { name = cssPrefixes[ i ] + capName; if ( name in style ) { return name; } } return origName; } function isHidden( elem, el ) { // isHidden might be called from jQuery#filter function; // in that case, element will be second argument elem = el || elem; return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );//动态创建的元素也是不包含也是隐藏 } // NOTE: we've included the "window" in window.getComputedStyle // because jsdom on node.js will break without it. function getStyles( elem ) { return window.getComputedStyle( elem, null );//封装 } function showHide( elements, show ) { var display, elem, hidden, values = [], index = 0, length = elements.length; for ( ; index < length; index++ ) { elem = elements[ index ]; if ( !elem.style ) { continue; } values[ index ] = data_priv.get( elem, "olddisplay" ); display = elem.style.display; if ( show ) { // Reset the inline display of this element to learn if it is // being hidden by cascaded rules or not if ( !values[ index ] && display === "none" ) { elem.style.display = ""; } // Set elements which have been overridden with display: none // in a stylesheet to whatever the default browser style is // for such an element if ( elem.style.display === "" && isHidden( elem ) ) { values[ index ] = data_priv.access( elem, "olddisplay", css_defaultDisplay(elem.nodeName) ); } } else { if ( !values[ index ] ) { hidden = isHidden( elem ); if ( display && display !== "none" || !hidden ) { //获取元素原来的显示样式,块级元素是block行内元素是inline data_priv.set( elem, "olddisplay", hidden ? display : jQuery.css(elem, "display") ); } } } } //每一个元素遍历 for ( index = 0; index < length; index++ ) { elem = elements[ index ]; if ( !elem.style ) {//有sytle属性通过style属性隐藏显示,没有就跳出。 continue; } if ( !show || elem.style.display === "none" || elem.style.display === "" ) { //values[ index ] || "",values[ index ]不存在时给空就是false,不直接写 = show ? 'block' :'none',因为是行内元素就不能是block而是in-line, //元素一上来是隐藏状态是获取不到元素的display属性是块级还是行内,调用show的时候通过elem.nodeName动态创建,获取元素是块级还是行内。 elem.style.display = show ? values[ index ] || "" : "none"; } } return elements; } jQuery.fn.extend({ //$('#div1').css('color','yellow'); css: function( name, value ) { return jQuery.access( this, function( elem, name, value ) { var styles, len, map = {}, i = 0; //$('#div1').css( ['color','backgroundColor','width'] ) if ( jQuery.isArray( name ) ) {//数组获取 styles = getStyles( elem ); len = name.length; for ( ; i < len; i++ ) { //调用jQuery.css()方法来获取 //jQuery.css方法多个值获取传了4个参数,第三个参数是false相当于没传,只是占位隔开第四个参数, map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); } return map; } return value !== undefined ? jQuery.style( elem, name, value ) ://设置:$('#div1').css('color','yellow') jQuery.css( elem, name );//获取:$('#div1').css('color'),单个值获取只传了2个参数,后面2个参数没传相当于是false, }, name, value, arguments.length > 1 ); }, show: function() { return showHide( this, true ); }, hide: function() { return showHide( this );//没传就是false }, toggle: function( state ) { if ( typeof state === "boolean" ) { return state ? this.show() : this.hide(); } return this.each(function() { if ( isHidden( this ) ) {//jQuery对象里面每一个元素是js节点对象 jQuery( this ).show(); } else { jQuery( this ).hide(); } }); } }); jQuery.extend({ // Add in style property hooks for overriding the default // behavior of getting and setting a style property cssHooks: { opacity: {//透明度处理 get: function( elem, computed ) { if ( computed ) { // We should always get a number back from opacity var ret = curCSS( elem, "opacity" ); return ret === "" ? "1" : ret; } } } }, // Don't automatically add "px" to these possibly-unitless properties cssNumber: { "columnCount": true, "fillOpacity": true, "fontWeight": true, "lineHeight": true, "opacity": true, "order": true, "orphans": true, "widows": true, "zIndex": true, "zoom": true }, // Add in properties whose names you wish to fix before // setting or getting the value cssProps: { // normalize float css property "float": "cssFloat" }, //设置:jQuery.style( $('#div1')[i], 'float','left' ) style: function( elem, name, value, extra ) { //元素节点的节点类型是3或者8, if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { return; } // Make sure that we're working with the right name var ret, type, hooks, origName = jQuery.camelCase( name ),//转驼峰,background-color --> backgroundColor style = elem.style;//元素的所有style //有就返回,没有就加入cssProps这个json,全部保存在$这个对象中。将float转成cssfloat, name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) ); // gets hook for the prefixed version // followed by the unprefixed version hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; // Check if we're setting a value if ( value !== undefined ) {//设置 type = typeof value; // convert relative number strings (+= or -=) to relative numbers. #7345 //$('#div1').css('width','+=100'); if ( type === "string" && (ret = rrelNum.exec( value )) ) { value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) ); // Fixes bug #9237 type = "number"; } // value是空或者无限大,设置时候就返回, if ( value == null || type === "number" && isNaN( value ) ) { return; } // origName不在jQuery.cssNumber中,在jQuery.cssNumber中不需要加单位。 if ( type === "number" && !jQuery.cssNumber[ origName ] ) { value += "px";//加单位 } // Fixes #8908, it can be done more correctly by specifying setters in cssHooks, // but it would mean to define eight (for every problematic property) identical functions if ( !jQuery.support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) { style[ name ] = "inherit"; } // If a hook was provided, use that value, otherwise just set the specified value if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) { style[ name ] = value;//没有兼容性,通过style.name = value设置 } } else {//获取 // If a hook was provided get the non-computed value from there if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) { return ret; } // 没有兼容性,通过style.name获取 return style[ name ]; } }, //获取:jQuery.css( $('#div1')[i], 'color' ); css: function( elem, name, extra, styles ) { var val, num, hooks, //$('#div1').css('background-color'); odiv.style.background-color是不行的,转驼峰成backgroundColor origName = jQuery.camelCase( name );//转驼峰, /* cssProps: { "float": "cssFloat" //class js中通过 className代表 }, */ //有就返回,没有就加入cssProps这个json,全部保存在$这个对象中。 name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) ); // gets hook for the prefixed version // followed by the unprefixed version hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; // 获取值的兼容性处理 if ( hooks && "get" in hooks ) { val = hooks.get( elem, true, extra ); } // 不做兼容性处理调用curCSS方法获取 if ( val === undefined ) { val = curCSS( elem, name, styles ); } /* cssNormalTransform = { letterSpacing: 0, fontWeight: 400 }, 返回的值是normal,并且属性名是letterSpacing、fontWeight就返回0、40 */ if ( val === "normal" && name in cssNormalTransform ) { val = cssNormalTransform[ name ]; } // 额外参数做判断 if ( extra === "" || extra ) { num = parseFloat( val );//123px转换成123 return extra === true || jQuery.isNumeric( num ) ? num || 0 : val; } return val; } }); //curCSS( $('#div1')[i], 'color') curCSS = function( elem, name, _computed ) { var width, minWidth, maxWidth, computed = _computed || getStyles( elem ),//getStyles调用原生window.getComputedStyle( elem, null );提高性能 // Support: IE9 // getPropertyValue is only needed for .css('filter') in IE9, see #12537 ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined, style = elem.style; if ( computed ) { //ownerDocument获取元素所在页面的document,动态创建一个元素var $span = $('<span>') 就不包含,调用jQuery.style方法来获取, if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { ret = jQuery.style( elem, name ); } // Support: Safari 5.1 // A tribute to the "awesome hack by Dean Edwards" // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values if ( rnumnonpx.test( ret ) && rmargin.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; }; function setPositiveNumber( elem, value, subtract ) { var matches = rnumsplit.exec( value ); return matches ? // Guard against undefined "subtract", e.g., when used as in cssHooks Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) : value; } function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { var i = extra === ( isBorderBox ? "border" : "content" ) ? // If we already have the right measurement, avoid augmentation 4 : // Otherwise initialize for horizontal or vertical properties name === "width" ? 1 : 0, val = 0; for ( ; i < 4; i += 2 ) { // both box models exclude margin, so add it if we want it if ( extra === "margin" ) { val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); } if ( isBorderBox ) { // border-box includes padding, so remove it if we want content if ( extra === "content" ) { val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); } // at this point, extra isn't border nor margin, so remove border if ( extra !== "margin" ) { val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); } } else { // at this point, extra isn't content, so add padding val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); // at this point, extra isn't content nor padding, so add border if ( extra !== "padding" ) { val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); } } } return val; } function getWidthOrHeight( elem, name, extra ) { // Start with offset property, which is equivalent to the border-box value var valueIsBorderBox = true, val = name === "width" ? elem.offsetWidth : elem.offsetHeight, styles = getStyles( elem ), isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; // some non-html elements return undefined for offsetWidth, so check for null/undefined // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285 // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668 if ( val <= 0 || val == null ) { // Fall back to computed then uncomputed css if necessary val = curCSS( elem, name, styles ); if ( val < 0 || val == null ) { val = elem.style[ name ]; } // Computed unit is not pixels. Stop here and return. if ( rnumnonpx.test(val) ) { return val; } // we need the check for style in case a browser which returns unreliable values // for getComputedStyle silently falls back to the reliable elem.style valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] ); // Normalize "", auto, and prepare for extra val = parseFloat( val ) || 0; } // use the active box-sizing model to add/subtract irrelevant styles return ( val + augmentWidthOrHeight( elem, name, extra || ( isBorderBox ? "border" : "content" ), valueIsBorderBox, styles ) ) + "px"; } //元素一上来是隐藏状态是获取不到元素的display属性是块级还是行内,调用show的时候通过elem.nodeName动态创建,获取元素是块级还是行内。 //css_defaultDisplay(elem.nodeName) elem.nodeName=div或者span function css_defaultDisplay( nodeName ) { var doc = document, /* elemdisplay = { BODY: "block" }, */ display = elemdisplay[ nodeName ]; if ( !display ) {//元素是body就是block,不是body就动态创建然后获取display属性,因为body不能动态创建 display = actualDisplay( nodeName, doc );//动态创建 // iframe情况 if ( display === "none" || !display ) { //动态创建iframe iframe = ( iframe || jQuery("<iframe frameborder='0' width='0' height='0'/>") .css( "cssText", "display:block !important" ) ).appendTo( doc.documentElement ); // Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse doc = ( iframe[0].contentWindow || iframe[0].contentDocument ).document; doc.write("<!doctype html><html><body>"); doc.close(); //获取iframe里面的节点的display属性 display = actualDisplay( nodeName, doc ); iframe.detach(); } // Store the correct default display elemdisplay[ nodeName ] = display; } return display; } // 动态创建元素actualDisplay( span, document ) function actualDisplay( name, doc ) { var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),//创建添加到body中,动态创建元素肯定是显示的, display = jQuery.css( elem[0], "display" );//获取display值 elem.remove(); return display; } jQuery.each([ "height", "width" ], function( i, name ) { jQuery.cssHooks[ name ] = { get: function( elem, computed, extra ) { if ( computed ) { // certain elements can have dimension info if we invisibly show them // however, it must have a current display style that would benefit from this 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 ); } }; }); // These hooks cannot be added until DOM ready because the support test // for it is not run until after DOM ready jQuery(function() { // Support: Android 2.3 if ( !jQuery.support.reliableMarginRight ) { jQuery.cssHooks.marginRight = { get: function( elem, computed ) { if ( computed ) { // Support: Android 2.3 // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right // Work around by temporarily setting element display to inline-block return jQuery.swap( elem, { "display": "inline-block" }, curCSS, [ elem, "marginRight" ] ); } } }; } // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084 // getComputedStyle returns percent when specified for top/left/bottom/right // rather than make the css module depend on the offset module, we just check for it here if ( !jQuery.support.pixelPosition && jQuery.fn.position ) { jQuery.each( [ "top", "left" ], function( i, prop ) { jQuery.cssHooks[ prop ] = { get: function( elem, computed ) { if ( computed ) { computed = curCSS( elem, prop ); // if curCSS returns percentage, fallback to offset return rnumnonpx.test( computed ) ? jQuery( elem ).position()[ prop ] + "px" : computed; } } }; }); } }); if ( jQuery.expr && jQuery.expr.filters ) { jQuery.expr.filters.hidden = function( elem ) { // Support: Opera <= 12.12 // Opera reports offsetWidths and offsetHeights less than zero on some elements return elem.offsetWidth <= 0 && elem.offsetHeight <= 0; }; jQuery.expr.filters.visible = function( elem ) { return !jQuery.expr.filters.hidden( elem ); }; } // These hooks are used by animate to expand properties jQuery.each({ margin: "", padding: "", border: "Width" }, function( prefix, suffix ) { jQuery.cssHooks[ prefix + suffix ] = { expand: function( value ) { var i = 0, expanded = {}, // assumes a single number if not a string parts = typeof value === "string" ? value.split(" ") : [ value ]; for ( ; i < 4; i++ ) { expanded[ prefix + cssExpand[ i ] + suffix ] = parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; } return expanded; } }; if ( !rmargin.test( prefix ) ) { jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; } });