如何通过JavaScript/jQuery获取CSS类的样式属性?

39

如何通过jQuery从CSS类中访问属性?我有一个类似于以下代码的CSS类:

.highlight { 
    color: red; 
}

我需要在一个对象上进行颜色动画:

$(this).animate({
    color: [color of highlight class]
}, 750);

因此,我可以在CSS中从红色更改为蓝色,并且我的动画将按照CSS的要求工作。

一种方法是放置一个带有highlight类的不可见元素,然后获取元素的颜色以在动画中使用,但我想这是一个非常糟糕的做法。

有什么建议吗?


2
@Cam 对于一些人来说,旧版浏览器的支持是必须的。遗憾的是,并不是每个人都可以忽略IE8。 - Benjamin Gruenbaum
1
你可以循环遍历样式表中的规则。疯狂的解决方案可以在这里找到:https://dev59.com/hHRC5IYBdhLWcg3wW_pk 另一个解决方案就是你已经建议的,只要在通用元素选择器上没有其他!important。 - epascarello
1
我认为创建一个不可见元素可能是最安全的选择。如果你只创造一个,那真的没有什么大问题。只要记住需要先创建它,然后获取颜色,然后销毁它,并且不要每次从中获取颜色,因为调用 $(".highlight").css 可能会覆盖它。另外唯一的解决方法就是使用 CSS 解析器,有一些实现,但是限制在于你需要在同一个域内的实际 CSS 文件,并且流程将会很复杂 js->ajax 到 css->解析->获取样式。 - Benjamin Gruenbaum
window.getComputedStyle(旧版IE也有相应的等效方法) - Prinzhorn
@badZoke如果我能在CSS文件和JavaScript文件中处理同一变量那就太好了,但我想我做不到。 - robsonrosa
显示剩余5条评论
8个回答

77

我写了一个小函数,遍历文档中的样式表,查找匹配的选择器,然后应用样式。

有一个注意点,这只适用于使用样式标签定义的样式表,或来自同一域的外部样式表。

如果已知样式表,则可以传入并避免查找多个样式表(更快速,并且如果存在冲突规则,则更精确)。

我仅在 jsFiddle 上进行了一些简单的测试,请告诉我这对你是否有效。

function getStyleRuleValue(style, selector, sheet) {
    var sheets = typeof sheet !== 'undefined' ? [sheet] : document.styleSheets;
    for (var i = 0, l = sheets.length; i < l; i++) {
        var sheet = sheets[i];
        if( !sheet.cssRules ) { continue; }
        for (var j = 0, k = sheet.cssRules.length; j < k; j++) {
            var rule = sheet.cssRules[j];
            if (rule.selectorText && rule.selectorText.split(',').indexOf(selector) !== -1) {
                return rule.style[style];
            }
        }
    }
    return null;
}

示例用法:

var color = getStyleRuleValue('color', '.foo'); // searches all sheets for the first .foo rule and returns the set color style.

var color = getStyleRuleValue('color', '.foo', document.styleSheets[2]); 

编辑:

我忽略了分组规则。我已将选择器检查更改为以下内容:

if (rule.selectorText.split(',').indexOf(selector) !== -1) {

现在它将检查分组规则中的任何选择器是否匹配。


1
非常好,你做得很棒。此外,请注意这里没有jQuery依赖,因此可以在任何项目中使用! - Benjamin Gruenbaum
@rlemon 在我的第四个表格中,sheet.cssRules为空,所以'sheet.cssRules.length'会抛出一个错误。我不知道为什么它是空的,但你可以在第二个'for'之前检查它是否为空。 - robsonrosa
1
@robsonrosa 我有两个看起来可行的解决方案,让我测试一下然后回复你。 - rlemon
@robsonrosa 更新了最后一次检查。另外,就像我之前提到的那样,我没有完全测试它。我可能会在本周撰写一篇博客文章,并真正深入研究测试用例,可能会为外部域表编写备用方案。 - rlemon
1
有用的函数。但它仍然不能处理像'.class,.class'这样带有空格的选择器。测试:http://jsfiddle.net/C7BAB/。因此,每个选择器都需要使用trim()。我试图编辑这个答案。 - And390
显示剩余13条评论

3

既然您已经在使用jQuery,尝试使用jQuery-ui的switchClass函数,它可以让您动画地切换到新颜色。

例如:

 $('div').switchClass( "", "highlight", 1000 );

演示


如果你不想在这里包含整个UI库,这是他们使用的代码:

switchClass: function( remove, add, speed, easing, callback) {
    return $.effects.animateClass.call( this, {
        add: add,
        remove: remove
    }, speed, easing, callback );
}

还有animateClass函数:

var classAnimationActions = [ "add", "remove", "toggle" ],
    shorthandStyles = {
        border: 1,
        borderBottom: 1,
        borderColor: 1,
        borderLeft: 1,
        borderRight: 1,
        borderTop: 1,
        borderWidth: 1,
        margin: 1,
        padding: 1
    };
function styleDifference( oldStyle, newStyle ) {
    var diff = {},
        name, value;




    for ( name in newStyle ) {
        value = newStyle[ name ];
        if ( oldStyle[ name ] !== value ) {
            if ( !shorthandStyles[ name ] ) {
                if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {
                    diff[ name ] = value;
                }
            }
        }
    }




    return diff;
}
function getElementStyles( elem ) {
    var key, len,
        style = elem.ownerDocument.defaultView ?
            elem.ownerDocument.defaultView.getComputedStyle( elem, null ) :
            elem.currentStyle,
        styles = {};




    if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {
        len = style.length;
        while ( len-- ) {
            key = style[ len ];
            if ( typeof style[ key ] === "string" ) {
                styles[ $.camelCase( key ) ] = style[ key ];
            }
        }
    // support: Opera, IE <9
    } else {
        for ( key in style ) {
            if ( typeof style[ key ] === "string" ) {
                styles[ key ] = style[ key ];
            }
        }
    }




    return styles;
}
$.effects.animateClass = function( value, duration, easing, callback ) {
    var o = $.speed( duration, easing, callback );

    return this.queue( function() {
        var animated = $( this ),
            baseClass = animated.attr( "class" ) || "",
            applyClassChange,
            allAnimations = o.children ? animated.find( "*" ).addBack() : animated;

        // map the animated objects to store the original styles.
        allAnimations = allAnimations.map(function() {
            var el = $( this );
            return {
                el: el,
                start: getElementStyles( this )
            };
        });

        // apply class change
        applyClassChange = function() {
            $.each( classAnimationActions, function(i, action) {
                if ( value[ action ] ) {
                    animated[ action + "Class" ]( value[ action ] );
                }
            });
        };
        applyClassChange();

        // map all animated objects again - calculate new styles and diff
        allAnimations = allAnimations.map(function() {
            this.end = getElementStyles( this.el[ 0 ] );
            this.diff = styleDifference( this.start, this.end );
            return this;
        });

        // apply original class
        animated.attr( "class", baseClass );

        // map all animated objects again - this time collecting a promise
        allAnimations = allAnimations.map(function() {
            var styleInfo = this,
                dfd = $.Deferred(),
                opts = $.extend({}, o, {
                    queue: false,
                    complete: function() {
                        dfd.resolve( styleInfo );
                    }
                });

            this.el.animate( this.diff, opts );
            return dfd.promise();
        });

        // once all animations have completed:
        $.when.apply( $, allAnimations.get() ).done(function() {

            // set the final class
            applyClassChange();

            // for each animated element,
            // clear all css properties that were animated
            $.each( arguments, function() {
                var el = this.el;
                $.each( this.diff, function(key) {
                    el.css( key, "" );
                });
            });

            // this is guarnteed to be there if you use jQuery.speed()
            // it also handles dequeuing the next anim...
            o.complete.call( animated[ 0 ] );
        });
    });
};

这里有一个包含所有必要功能的可工作范例:http://jsfiddle.net/maniator/3C5ZQ/


这意味着包含另一个巨大的外部库(jQueryUI)。 - Benjamin Gruenbaum
@BenjaminGruenbaum 你不需要包含整个东西,只需从jQuery UI网站中包含此函数即可。 - Naftali
@Neal 这可能是我(我正在使用jQueryUI)的一个很好的解决方案(也许是最好的解决方案),非常感谢,但我不会投票支持它(或“接受”它),因为它没有回答问题。 - robsonrosa
@robsonrosa 为什么它没有回答问题? - Naftali
2
@Neal 对不起,我的英语不好。你的回答没有解释如何通过jQuery从CSS类中获取样式属性,但正是我所需要的。 - robsonrosa
显示剩余2条评论

2
这里还有另一种方法:添加一个带有应用类的隐藏div。使用jQuery.css查找样式值,然后删除该元素。

http://plnkr.co/edit/Cu4lPbaJWHW42vgsk9ey

function getStyleValue(className, style) {
  var elementId = 'test-' + className,
    testElement = document.getElementById(elementId),
    val;

  if (testElement === null) {
    testElement = document.createElement('div');
    testElement.className = className;
    testElement.style.display = 'none';
    document.body.appendChild(testElement);
  }

  val = $(testElement).css(style);
  document.body.removeChild(testElement);
  return val;
}

console.log( 'The style value is ' + getStyleValue('dark-red', 'color') );

2

这个怎么样?

$('<span class="highlight"></span>').appendTo('body');
$(this).animate({
    color: $('.highlight').css('color')
}, 750);
$('.highlight').remove();

虽然有点不太规范,但这样做可以提供一个(空的)元素来引用,以获取您正在寻找的CSS值。

更新 这里有一个来自CSS解析器/抽象器的不错解决方案?如何将样式表转换为对象

function findColorProperty(selector) {
    rules = document.styleSheets[0].cssRules
    for(i in rules) {
        //if(rules[i].selectorText==selector) 
            //return rules[i].cssText; // Original
        if(rules[i].selectorText == selector) 
            return rules[i].style.color; // Get color property specifically
    }
    return false;
}

用法

$(this).animate({
    color: findColorProperty('.highlight')
}, 750);

这里有一个fiddle http://jsfiddle.net/wzXDx/1/。由于嵌入环境的特性,我不得不使用styleSheets[1]才能使其在fiddle中正常工作。


不要忘记删除添加的 span :-PTranslated to Chinese: - Naftali
1
@BenjaminGruenbaum 更新了,提供了一个实际的解决方案。 :) - Joe
那是个坏主意,乔……这样你会移除所有页面上的高亮而不仅仅是你创建的那一个。 - Naftali
1
@Neal 我的想法是页面上没有.highlight。如果有,那么问题的提出者不是应该使用.css()而不是整个样式表解析过程吗? - Joe

2
我想到的唯一解决方案是以下内容:

//create an element with this class and append it to the DOM
var eleToGetColor = $('<div class="highlight" style="display: none;">').appendTo('body');
//get the color of the element
var color = eleToGetColor.css('color');
//completly remove the element from the DOM
eleToGetColor.remove();


$("div").animate({
  //set the new color
  color: color,
}, 1000);
.highlight {
  color: red;
}
div {
  width: 200px;
  height: 100px;
  color: blue;
  font-size: 6em;
  font-weight: bold;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.3/themes/smoothness/jquery-ui.css" />
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.3/jquery-ui.min.js"></script>
<div>TEST</div>


1

我刚刚写了一个函数,通过选择器获取所有的样式。注意:选择器必须与CSS中的相同。

    /**
     * Gets styles by a classname
     * 
     * @notice The className must be 1:1 the same as in the CSS
     * @param string className_
     */
    function getStyle(className_) {

        var styleSheets = global_.document.styleSheets;
        var styleSheetsLength = styleSheets.length;
        for(var i = 0; i < styleSheetsLength; i++){
            var classes = styleSheets[i].rules || styleSheets[i].cssRules;
            var classesLength = classes.length;
            for (var x = 0; x < classesLength; x++) {
                if (classes[x].selectorText == className_) {
                    var ret;
                    if(classes[x].cssText){
                        ret = classes[x].cssText;
                    } else {
                        ret = classes[x].style.cssText;
                    }
                    if(ret.indexOf(classes[x].selectorText) == -1){
                        ret = classes[x].selectorText + "{" + ret + "}";
                    }
                    return ret;
                }
            }
        }

    }

1
为什么不添加.highlighted类,缓存颜色样式,然后将其移除并动画到缓存的颜色?即不要附加元素,也不要解析和循环样式。 jsfiddle示例

var $element = $('.my-class').addClass('highlighted');
var colorToAnimate = $element.css('color');

$element.removeClass('highlighted');

alert(colorToAnimate);
.my-class {
  color: blue;
}
.highlighted {
  color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<span class="my-class">Animated color text</span>


1

很遗憾,我不能对这个很棒的答案发表评论,但我找到了一个未被考虑到的情况(当CSS类被多次声明且第一个声明没有你想要的样式时),制作了一个jsFiddle来解决它:

function getStyleRuleValue(style, selector, sheet) {
  var sheets = typeof sheet !== 'undefined' ? [sheet] : document.styleSheets;
  for (var i = 0, l = sheets.length; i < l; i++) {
    var sheet = sheets[i];
    if( !sheet.cssRules ) { continue; }
    for (var j = 0, k = sheet.cssRules.length; j < k; j++) {
      var rule = sheet.cssRules[j];
      if (rule.selectorText && rule.selectorText.indexOf(selector) !== -1 && rule.style[style] !== '') {
        return rule.style[style];
      }
    }
  }
  return null;
}

还删除了条件语句中的分割符号,这是不必要的,现在可以确认样式是否存在于正在检查的规则中。

只是为了好玩,创建了一个jsFiddle来按选择器缓存样式:

var styleCache = {};

function getStyleRuleValue(style, selector, sheet) {
  if (typeof styleCache[selector] !== 'undefined') {
    if (typeof styleCache[selector][style] !== 'undefined') {
        return styleCache[selector][style];
    }
  }
  else {
    styleCache[selector] = {};
  }

  var sheets = typeof sheet !== 'undefined' ? [sheet] : document.styleSheets;
  for (var i = 0, l = sheets.length; i < l; i++) {
    var sheet = sheets[i];
    if( !sheet.cssRules ) { continue; }
    for (var j = 0, k = sheet.cssRules.length; j < k; j++) {
      var rule = sheet.cssRules[j];
      if (rule.selectorText && rule.selectorText.indexOf(selector) !== -1 && rule.style[style] !== '') {
        return styleCache[selector][style] = rule.style[style];
      }
    }
  }
  return null;
}

尽管如此,如果您确实使用它,我建议将其放在闭包/类中。再次感谢rlemon提供的出色原始代码。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接