代码改变世界

jQuery css

2013-01-21 11:47  Justany_WhiteSnow  阅读(2791)  评论(0编辑  收藏  举报

jQuery css模块用于css属性的修改操作。

 

jQuery.fn.css

jQuery.fn.css = function( name, value ) {
    //又是用access来操作
    return jQuery.access( this, function( elem, name, value ) {
        var styles, len,
            map = {},
            i = 0;
        
        //如果name是数组
        if ( jQuery.isArray( name ) ) {
            //通过getStyles方法返回elem的styles
            styles = getStyles( elem );
            len = name.length;

            //创建对应styles的处理函数map
            for ( ; i < len; i++ ) {
                map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
            }

            return map;
        }

        //如果不是数组,则返回jQuery.style或jQuery.css
        return value !== undefined ?
            jQuery.style( elem, name, value ) :
            jQuery.css( elem, name );
    }, name, value, arguments.length > 1 );
};

又是通过jQuery.access来遍历和操作属性。

根据value值来判断是返回一个函数数组,还是返回一个函数传入jQuery.access。

主要用到jQuery.css和jQuery.style两个方法。

 

getStyles

function getStyles( elem ) {
    return window.getComputedStyle( elem, null );
}

这是一个获取实际css style的方法。

可是……getComputedStyle是啥东西……

getComputedStyle是一个可以获取当前元素所有最终使用的CSS属性值。返回的是一个CSS样式声明对象([object CSSStyleDeclaration]),只读。

语法:

var styles = window.getComputedStyle("元素", "伪类");

如果没有伪类,则传null。

实际上就是获取最终浏览器绘制时的css值,因为style不会返回所有css值,只会返回设置的css值,所以需要用该方法来获得所有css值。

限于篇幅本文就不详细解释了,有兴趣的朋友请参见:获取元素CSS值之getComputedStyle方法熟悉

 

jQuery.style

jQuery.style = function( elem, name, value, extra ) {
    // 不处理text和comment节点
    if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
        return;
    }

    var ret, type, hooks,
        //修正css属性名
        origName = jQuery.camelCase( name ),
        style = elem.style;

    //jQuery.cssProps是css缓存,如果有则取出值,否则通过vendorPropName函数来得到实际的css名字
    name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );

    // 获取必要的钩子
    hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];

    // 如果value已定义
    if ( value !== undefined ) {
        type = typeof value;

        // 如果value是+=或则-=一个数,则转成对应的数字
        if ( type === "string" && (ret = rrelNum.exec( value )) ) {
            value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
            // 将其类型改成number
            type = "number";
        }

        // 确保NaN和null不被设置
        if ( value == null || type === "number" && isNaN( value ) ) {
            return;
        }

        // 如果value是数字则加上px
        if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
            value += "px";
        }

        // 修复#8908,IE9的问题,对于克隆的元素清除掉其background时,其原型的background也会被清除
        if ( !jQuery.support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) {
            style[ name ] = "inherit";
        }

        // 如果钩子存在,则使用钩子设置值,否则用style[ name ]来设置值
        if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
            style[ name ] = value;
        }

    } else {
        // 如果钩子存在,则使用钩子返回值
        if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
            return ret;
        }

        // 否则用style[ name ]来返回值
        return style[ name ];
    }
};

这里面有一个挺有趣的问题。下面两个代码最后结果是多少呢?

alert(("-" + 5) + 6);
alert(("-" + 5) * 6);

 

jQuery.css

jQuery.css = function( elem, name, extra, styles ) {
    var val, num, hooks,
        origName = jQuery.camelCase( name );

    // 修正名字name
    name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );

    // 得到必要的钩子
    hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];

    // 如果有钩子则使用get来获取值
    if ( hooks && "get" in hooks ) {
        val = hooks.get( elem, true, extra );
    }

    // 没有钩子则用curCSS函数获取
    if ( val === undefined ) {
        val = curCSS( elem, name, styles );
    }

    // 将"normal"转成特定的值
    if ( val === "normal" && name in cssNormalTransform ) {
        val = cssNormalTransform[ name ];
    }

    // 是否需要强行转成数字或者true
    if ( extra === "" || extra ) {
        num = parseFloat( val );
        return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
    }
    return val;
};

 

curCSS函数

var curCSS = function( elem, name, _computed ) {
    var width, minWidth, maxWidth,
        computed = _computed || getStyles( elem ),

        // 解决IE9的问题,getPropertyValue用IE9中用.css('filter')
        ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined,
        style = elem.style;

    // 如果实际styles数组存在
    if ( computed ) {

        //如果ret为"",且elem不是子文档(没有style)
        if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
            ret = jQuery.style( elem, name );
        }

        // 支持:Chrome < 17,Safari 5.1
        // 来自Dean Edwards帅呆的hack
        // 将百分比转成更加有用的px
        if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {

            // 记住原始值
            width = style.width;
            minWidth = style.minWidth;
            maxWidth = style.maxWidth;

            // 通过改变minWidth、maxWidth、width得到相应的px值
            style.minWidth = style.maxWidth = style.width = ret;
            ret = computed.width;

            // 再将原来的值赋回去
            style.width = width;
            style.minWidth = minWidth;
            style.maxWidth = maxWidth;
        }
    }

    return ret;
};

 Dean Edwards的hack主要利用的是部分浏览器会使用计算值来表示元素宽度,而非使用值。

 

show & hide

jQuery.fn.show = function() {
    return showHide( this, true );
};

jQuery.fn.show直接引用showHide函数,jQuery.fn.hide也是一样:

jQuery.fn.hide = function() {
    return showHide( this );
};

而jQuery.fn.toggle则可接受state或者通过判断当前元素是否hidden,再调用jQuery.fn.show或者jQuery.fn.hide。

jQuery.fn.toggle = function( state ) {
    var bool = typeof state === "boolean";

    return this.each(function() {
        if ( bool ? state : isHidden( this ) ) {
            jQuery( this ).show();
        } else {
            jQuery( this ).hide();
        }
    });
};

 

showHide函数

function showHide( elements, show ) {
    var elem,
        values = [],
        index = 0,
        length = elements.length;

    // 遍历所有元素
    for ( ; index < length; index++ ) {
        elem = elements[ index ];
        //如果元素没有style属性,则跳过
        if ( !elem.style ) {
            continue;
        }
        //取出保存在缓存的olddisplay值
        values[ index ] = jQuery._data( elem, "olddisplay" );
        //如果要显示
        if ( show ) {
            // 通过将display设置成"",来判断""元素是否会显示
            if ( !values[ index ] && elem.style.display === "none" ) {
                elem.style.display = "";
            }

            // 如果display被设成了"",并且元素隐藏了,则通过css_defaultDisplay设置默认显示方法
            if ( elem.style.display === "" && isHidden( elem ) ) {
                values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) );
            }
        //如果缓存没有值,且元素没有隐藏
        } else if ( !values[ index ] && !isHidden( elem ) ) {
            //将目前的display值保存入缓存
            jQuery._data( elem, "olddisplay", jQuery.css( elem, "display" ) );
        }
    }

    // 在第二次循环设置display属性,避免不断回流
    for ( index = 0; index < length; index++ ) {
        elem = elements[ index ];
        if ( !elem.style ) {
            continue;
        }
        if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
            // 是否要西那是,要显示则设置成缓存值或者"",否则设置为"none"
            elem.style.display = show ? values[ index ] || "" : "none";
        }
    }

    return elements;
}