简体   繁体   中英

Vanilla JavaScript: Is there a way to toggle multiple CSS-classes in one statement?

I use these JavaScript-code to change classes in my script:

var toggleDirection = function() {
  group.classList.toggle('left-to-right');
  group.classList.toggle('right-to-left');
}

In my example there a only two classes to change but could be also multiple classes...

So therefore: Does anyone know a way to write the example less redundant?

No it is not possible using Element.classList API directly. Looking at API you can read:

toggle ( String [, force] ) When only one argument is present: Toggle class value; ie, if class exists then remove it, if not, then add it. When a second argument is present: If the second argument is true, add specified class value, and if it is false, remove it.

Reference here .

You could potentially write your own "utility" function (in vanilla JS) which does what you want, below a very simple demonstrative example which work on top of the classList API:

var superToggle = function(element, class0, class1) {
  element.classList.toggle(class0);
  element.classList.toggle(class1);
}

And you call it in this way:

superToggle(group,'left-to-right', 'right-to-left');

For anyone looking for a short answer, you can do this on one line using the rest parameter introduced in ES6/ES2015:

const toggleCSSclasses = (el, ...cls) => cls.map(cl => el.classList.toggle(cl))

This is pretty close to @attacomsian's answer , but taking advantage of the fact that the rest parameter will return an array - no matter how many arguments is being passed to the function. Which means we can skip the part where we detect whether we're working with a string or an array.

 const toggleCSSclasses = (el, ...cls) => cls.map(cl => el.classList.toggle(cl)); const one = document.querySelector(".one"); one.addEventListener("click", () => { toggleCSSclasses(one, "class1"); }); const two = document.querySelector(".two"); two.addEventListener("click", () => { toggleCSSclasses(two, "class1", "class2"); });
 .class1 { text-decoration: underline } .class2 { background: steelblue }
 <p class="one">Click to toggle one class</p> <p class="two">Click to toggle two classes</p>

just use the map array.

like

['left-to-right', 'right-to-left'].map(v=> group.classList.toggle(v) )

You can extend the DOMTokenList object with the following multiToggle

if (window["DOMTokenList"]) //check if DOMTokenList is an existing object.
{
//multitoggle
DOMTokenList.prototype.multiToggle = function()
{
    if (arguments.length > 0) // there needs to be at least one object
    {
        for (argument in arguments) //loop all arguments
        {
            var argument = arguments[argument];
            //All primitives are allowed as input (Symbol not included). If not a primitive, raise error.
            if (Object.prototype.toString.call(argument) !== "[object Undefined]" && Object.prototype.toString.call(argument) !== "[object Null]" && Object.prototype.toString.call(argument) !== "[object String]" && Object.prototype.toString.call(argument) !== "[object Number]" && Object.prototype.toString.call(argument) !== "[object Boolean]")   
            {
                throw new SyntaxError;
            }
            else
            {
                if (this.contains(argument)) //check if classList contains the argument.
                {
                    this.remove(argument); //if so remove
                }
                else
                {
                    this.add(argument); //if not add
                }                   
            }
        }
    }
    else
    {
        throw new Error("The argument is not optional");
    }
    return undefined; //return undefined as with add and remove.
}       
}

multiToggle does not have the force ability of the original toggle . It just turns class names on and off for as many arguments as supplied.

Warning, expanding fixed Objects can cause troubles in the future . When an object gets deprecated or changed your functionality could break, requiring to more maintenance.

There is no direct way but you can create a helper function:

const toggleClass =  (el, cls) => {
    if (Array.isArray(cls)) {
        cls.map((cl) => {
            el.classList.toggle(cl);
        });
    } else {
        el.classList.toggle(cls);
    }
};

Now just call toggleClass() like below:

// single class
toggleClass(document.querySelector('body'), 'left-to-right');
//multiple classes
toggleClass(document.querySelector('body'), ['left-to-right', 'right-to-left']);

If I need to toggle multiple classes I just create an array and then iterate through it.

  var classes = [
    "red",
    "blue",
    "green",
    "purple"
  ]

  for (var i = 0; i < classes.length; i++){
    p.classList.toggle(classes[i])
  }

Here is ES6 version of solution

const classToggle = (el, ...args) => args.map(e => el.classList.toggle(e))

 const classToggle = (el, ...args) => { args.map(e => el.classList.toggle(e)) }
 .a { color: red } .b { background: black } .c { border-color: yellow }
 <button onclick="classToggle(this,'a', 'c','b')" class="abc ">Click me</button>

And here's old JS code:

var classToggle = function classToggle(el) {
  for (
    var _len = arguments.length,
      args = new Array(_len > 1 ? _len - 1 : 0),
      _key = 1;
    _key < _len;
    _key++
  ) {
    args[_key - 1] = arguments[_key];
  }

  args.map(function (e) {
    return el.classList.toggle(e);
  });
};

Answer from year 2020 here!

Found this article helpful from 4/2021

Can use comma separated list of classes like this:

const button = document.getElementById('button')

button.classList.add('btn', 'btn-primary', 'btn-primary--footer')
button.classList.remove('btn', 'btn-primary', 'btn-primary--footer')

or even spread syntax from a list of classes:

const button = document.getElementById('button')
const classes = ['btn', 'btn-primary', 'btn-primary--footer']

button.classList.add(...classes)
button.classList.remove(...classes)

Assuming that myElement is a valid DOM Element, this works:

['right-to-left', 'left-to-right'].forEach(function(className){
  this.classList.toggle(className);
}, myElement);

This Worked for me

let superToggle = (element, class0, class1) => {
 element.classList.toggle(class0);
 element.classList.toggle(class1);
};
const toggleClasses = (e, classes) => {
  classes.forEach((className) => {
    e.classList.toggle(className)
  });
}

const classes = [
  'hidden',
  'bg-white',
]

toggleClasses(element, classes)

The following should work; granted that these class-names are defined in your CSS and some elements on the current page have these classNames:

var toggleDirection = function()
{
    var ltr, rtl, lst, cls;

    ltr = 'left-to-right';
    rtl = 'right-to-left';
    lst = [].slice.call(document.getElementsByClassName(ltr));

    lst = ((lst.length > 0) ? lst : [].slice.call(document.getElementsByClassName(rtl)));

    lst.forEach
    (
        function(node)
        {
            cls = node.getAttribute('class');

            if (cls.indexOf(ltr) > -1)
            { cls.split(ltr).join(rtl); }
            else
            { cls.split(rtl).join(ltr); }

            node.setAttribute('class', cls);
        }
    );
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM