jQuery: Rotating elements through a set of classes

2019-05-11 12:02发布

toggleClass is great if I just have two presentations styles I want to use, but a lot of times I've got more than two states that I want to use.

For example, if I want to rotate through three classes:

if ($(this).hasClass("A"))
   $(this).removeClass("A").addClass("B");
else if ($(this).hasClass("B"))
   $(this).removeClass("B").addClass("C");
else if ($(this).hasClass("C"))
   $(this).removeClass("C").addClass("A");

I'd like to have a simple method that did this for me, something like:

$(this).rotateClass('A', 'B', 'C');

Is there an existing jQuery method or plugin that does this?

标签: jquery class
6条回答
可以哭但决不认输i
2楼-- · 2019-05-11 12:42

Put them in an Array:

var arr = ['A', 'B', 'C'];
var i = 0;

Then in the handler:

i = ++i % arr.length;

$(this).toggleClass( this.className + ' ' + arr[ i ] );

The use of this.className assumes that there's not other classes applied to this element.

JSFIDDLE DEMO


If there may be other classes, use this:

$(this).removeClass( arr[ i ] );
i = ++i % arr.length;
$(this).addClass( arr[ i ] );

JSFIDDLE DEMO


If there may be other elements, and each need their own state, you could use a closure to associate a unique i with each element:

$('div').each(function() {
    var i = 0;

    $(this).click(function() {
        $(this).removeClass( arr[ i ] );
        i = ++i % arr.length;
        $(this).addClass( arr[ i ] );
    });
});

JSFIDDLE DEMO

查看更多
Lonely孤独者°
3楼-- · 2019-05-11 12:42

My current solution:

$.fn.mapClasses = function(mapping){
  return this.each(function(){
    this.className = this.className.split(/\s+/).map(function(klass){
      return mapping[klass] || klass
    }).join(' ');
  });
};
$.fn.rotateClasses(){
  var mapping = {};
  var prev = arguments[0];
  for (var i = arguments.length - 1; i >= 0; i--){
    mapping[ arguments[i] ] = prev;
    prev = arguments[i];
  }
  return this.mapClasses(mapping);
};
查看更多
冷血范
4楼-- · 2019-05-11 12:43

This plugin code will rotate between the passed classes (however many there are (2-n). If none of the passed classes are found on the object, then the first class is set.

$.fn.rotateClass(/* pass multiple class names here */) {
    for (var i = 0; i < arguments.length; i++) {
        if (this.hasClass(arguments[i])) {
            this.removeClass(arguments[i]));
            i++;
            if (i >= arguments.length) {
                i = 0;
            }
            this.addClass(arguments[i]);
            return(this);
        }
    }
    // none found so set the first class
    if (arguments.length > 0) {
        this.addClass(arguments[0]);
    }
    return(this);
}

This version of the code assumes that you are applying the same classes to all the DOM objects in the jQuery object and they all have the same state. It could be extended to treat each DOM object in the jQuery object separately and rotate each ones separately if that was required.

查看更多
Ridiculous、
5楼-- · 2019-05-11 12:51

You can still use toggleClass and pass it a function instead:

$(this).toggleClass(function() {
    if ($(this).hasClass('red')) {
      return 'green red';
    }

    if ($(this).hasClass('green')) {
      return 'blue green';
    }

    if ($(this).hasClass('blue')) {
      return 'red blue';
    }
});

Not the easiest code to maintain though, so it would probably be better to wrap it in a plugin.

http://jsbin.com/inaduy/edit#javascript,html,live

And now made in to a very basic plugin (that needs a bit of validation). You just pass an array of objects containing pairs of classes to swap.

var classArray = [{current: 'red', next:'green'}, {current:'green', next:'blue'}, {current:'blue', next:'red'}];

$('#hello').click(function() {
  $(this).toggleRotate(classArray);
});

(function($) {
  $.fn.toggleRotate = function(classes) {

    return $(this).toggleClass(function() {
      var l = classes.length;
      for (var i = 0; i < l; i++) {
        if ($(this).hasClass(classes[i].current)) {
          return classes[i].current + ' ' + classes[i].next;
        }        
      }
      // If it makes it here return the first current value
      return classes[0].current;
    });
  };
})(jQuery);

http://jsbin.com/inaduy/2/edit

查看更多
仙女界的扛把子
6楼-- · 2019-05-11 12:56

Here's my attempt at it.

  $.fn.rotate= function( classes ) {
      $element = this;  // element the rotate is being applied to
      for( var i = 0; i <  classes.length; i++ ){   // look through the classes array
          if( $element.hasClass( classes[i] ) ){  // check if current element has the class specified in the array 
              $element.removeClass( classes[i] );  // if it does then remove the class 
              $element.addClass( classes[ ++i % classes.length ] );  
              return $element; // return the current element so other functions can be applied to it. 
           }
      }
  }

You would use it by calling .rotate on the element and passing in an array of classes to rotate.

Here's an interactive demo. I just added the animate to show that you can apply other jQuery functions to the element after the rotate is finished.

 $('#test').rotate(['A','B','C']); 

The reason we use the modulus operator is, if i > the length of the array then we want the correct index. E.g array of classes is ['A','B','C'], if the current class on our element is 'C' then the index of the current class is 2 (arrays are 0 index based), then if we increment 2 + 1 = 3 to get the class we want to rotate it to but we don't have any class at index 3 hence 3 % 3  = 0 which is the index of 'A', that's what we want, hence the modulus will get us the correct index every time. 

查看更多
虎瘦雄心在
7楼-- · 2019-05-11 12:59

Here's what I use:

$.fn.rotateClass = function(classes) {
    var $set = this.each(function () {
        var $this = $(this);
        var index = (($this.data("currentClassIndex")) ? $this.data("currentClassIndex") : 0) % classes.length;

        $this.removeClass(classes.join(" "))
             .addClass(classes[index])
             .data("currentClassIndex", ++index);
    });

    return $set;
}

No for loops, no hasClass calls, compatible with sets of elements, very compact and very performant.

Usage:

$("#randomDiv").rotateClass(["classA", "classB", "classC", "classD"]);
查看更多
登录 后发表回答