37

如何通过 jQuery 从 CSS 类中访问属性?我有一个 CSS 类,例如:

.highlight { 
    color: red; 
}

我需要对一个对象做一个彩色动画:

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

这样我就可以从更改redblue(在 CSS 中)并且我的动画将按照我的 CSS 工作。

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

有什么建议么?

4

8 回答 8

74

我写了一个小函数,它遍历文档上的样式表,寻找匹配的选择器,然后是样式。

有一个警告,这仅适用于使用样式标记定义的样式表,或来自同一域的外部表。

如果这张纸是已知的,你可以把它传进去,这样你就不必查看多张纸了(更快,如果你有冲突的规则,那就更准确了)。

我只用一些弱测试用例在 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) {

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

于 2013-06-06T15:47:05.397 回答
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 fn:

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/

于 2013-06-06T15:27:08.077 回答
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>

于 2015-04-03T11:56:51.957 回答
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);

这是一个小提琴http://jsfiddle.net/wzXDx/1/styleSheets[1]由于环境的嵌入式特性,我不得不使用它来让它在小提琴中工作。

于 2013-06-06T15:18:07.857 回答
1

这是另一种方法:添加应用了类的隐藏 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') );
于 2015-03-23T22:34:33.057 回答
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;
                }
            }
        }

    }
于 2014-12-17T14:07:12.543 回答
1

为什么不添加.highlighted类,缓存color样式,而不是删除它并为缓存的颜色设置动画?即不附加元素,不解析和循环样式。

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>

于 2015-04-02T12:44:02.550 回答
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;
}

还取出了条件中的拆分,没有必要,现在它确认样式存在于正在检查的规则中。

只是为了 shigiggles 创建了一个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的精彩原创作品。

于 2017-02-10T07:47:01.610 回答