zoukankan      html  css  js  c++  java
  • jquery源码09 (6058 , 6620) css() : 样式的操作

    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;
        }
    });
  • 相关阅读:
    Mybatis整理
    Spring获取json和表单
    Mqtt(paho)重连机制
    Redis无法获取资源(Could not get a resource from the pool)
    SSM+Maven+Redis框架学习
    第一章 Zookeeper理论基础
    RocketMQ和Kafka对比
    Kafka工作原理与过程
    Kafka介绍
    JVM调优
  • 原文地址:https://www.cnblogs.com/yaowen/p/6948985.html
Copyright © 2011-2022 走看看