How to get a style attribute from a CSS class by j

2019-01-01 13:33发布

How can I access a property from a CSS class by jQuery? I have a CSS class like:

.highlight { 
    color: red; 
}

And I need to do a color animation on an object:

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

So that I can change from red to blue (in the CSS) and my animation will work in accordance with my CSS.

One approach would be to place an invisible element with the highlight class and then get the color of the element to use in the animation, but I guess this is a very, very bad practice.

Any suggestions?

8条回答
何处买醉
2楼-- · 2019-01-01 13:57

I wrote a small function that traverses the stylesheets on the document looking for the matched selector, then style.

There is one caveat, this will only work for style sheets defined with a style tag, or external sheets from the same domain.

If the sheet is known you can pass it in and save yourself from having to look in multiple sheets (faster and if you have colliding rules it's more exact).

I only tested on jsFiddle with some weak test cases, let me know if this works for you.

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;
}

example usage:

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]); 

edit:

I neglected to take into consideration grouped rules. I changed the selector check to this:

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

now it will check if any of the selectors in a grouped rules matches.

查看更多
闭嘴吧你
3楼-- · 2019-01-01 13:58

Here's another method: add a hidden div with the class applied. Use jQuery.css to look up the style value. Then remove the element.

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') );
查看更多
笑指拈花
4楼-- · 2019-01-01 13:59

Why don't add .highlighted class, cache the color style, than remove it and animate to cached color? I.e. don't append elements and don't parse & loop styles.

jsfiddle example

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>

查看更多
回忆,回不去的记忆
5楼-- · 2019-01-01 14:03

Since you are already using jQuery try using the jQuery-ui's function switchClass which would allow you to animate to this new color.

For example:

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

Demo


In case you do not want to include the whole UI library here is the code they use:

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

And the 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 ] );
        });
    });
};

Working fiddle with all the functions that are needed: http://jsfiddle.net/maniator/3C5ZQ/

查看更多
与君花间醉酒
6楼-- · 2019-01-01 14:09

How about this?

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

It's kind of dirty but will give you an (empty) element to reference to get the CSS value for which you are looking.

Update Here is a decent solution from CSS parser/abstracter? How to convert stylesheet into object

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;
}

Usage

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

Here is a fiddle http://jsfiddle.net/wzXDx/1/. I had to use styleSheets[1] to get this to work in the fiddle due to the embedded nature of the environment.

查看更多
人间绝色
7楼-- · 2019-01-01 14:11

Unfortunately I can't comment on this awesome answer, but found a case that isn't catered for (when CSS class is declared multiple times and the first declaration doesn't have the style you're looking for), made a jsFiddle to cater for it:

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;
}

Also took out the split in the conditional, not necessary and now it confirms that the style is present in the rule being checked.

Just for shigiggles created a jsFiddle to cache the styles by selector:

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;
}

Although if you do use that, I would suggest putting it in a closure/class. Thanks again to rlemon for the awesome original.

查看更多
登录 后发表回答