【问题标题】:Is there a way to add/remove several classes in one single instruction with classList?有没有办法使用 classList 在一条指令中添加/删除多个类?
【发布时间】:2012-06-20 08:54:28
【问题描述】:

到目前为止,我必须这样做:

elem.classList.add("first");
elem.classList.add("second");
elem.classList.add("third");

虽然这在 jQuery 中是可行的,像这样

$(elem).addClass("first second third");

我想知道是否有任何本地方法可以添加或删除。

【问题讨论】:

    标签: javascript html


    【解决方案1】:
    elem.classList.add("first");
    elem.classList.add("second");
    elem.classList.add("third");
    

    相等

    elem.classList.add("first","second","third");
    

    【讨论】:

    • 如果你想应用几个类名的数组,你必须调用: DOMTokenList.prototype.add.apply(elem.classList, ['first', 'second', 'third ']);
    • 在撰写本文时,Firefox 也不支持它。 My answer 提供了一个 polyfill。
    • 你考虑过 el.className += "my classes here"
    • 有没有办法删除多个类
    • @Vicky elem.classList.remove("first","second","third"); addremove 方法都基于相同的 DOMTokenList
    【解决方案2】:

    新的spread operator 使得将多个 CSS 类应用为数组变得更加容易:

    const list = ['first', 'second', 'third'];
    element.classList.add(...list);
    

    【讨论】:

    • 接受的答案适用于直接的值列表,但这个适用于数组......看起来都是很好的答案!
    • 我可以使用DOMTokenList 代替数组吗?我知道 DOMTokenList 是一个类似数组的对象。那么可以通过classList.add() 方法使用它还是必须将 DOMTokenList 转换为真实数组?
    【解决方案3】:

    你可以像下面那样做

    添加

    elem.classList.add("first", "second", "third");
    

    删除

    elem.classList.remove("first", "second", "third");
    

    Reference

    TLDR;

    在直截了当的情况下,上述删除应该可以工作。但是在删除的情况下,您应该在删除它们之前确保类存在

    const classes = ["first","second","third"];
    classes.forEach(c => {
      if (elem.classList.contains(c)) {
         element.classList.remove(c);
      }
    })
    

    【讨论】:

      【解决方案4】:

      classList 属性确保不会将重复的类不必要地添加到元素中。为了保留这个功能,如果你不喜欢简写版本或 jQuery 版本,我建议在DOMTokenList 中添加一个addMany 函数和removeManyclassList 的类型):

      DOMTokenList.prototype.addMany = function(classes) {
          var array = classes.split(' ');
          for (var i = 0, length = array.length; i < length; i++) {
            this.add(array[i]);
          }
      }
      
      DOMTokenList.prototype.removeMany = function(classes) {
          var array = classes.split(' ');
          for (var i = 0, length = array.length; i < length; i++) {
            this.remove(array[i]);
          }
      }
      

      这些将可以像这样使用:

      elem.classList.addMany("first second third");
      elem.classList.removeMany("first third");
      

      更新

      根据您的 cmets,如果您只想在未定义的情况下为它们编写自定义方法,请尝试以下操作:

      DOMTokenList.prototype.addMany = DOMTokenList.prototype.addMany || function(classes) {...}
      DOMTokenList.prototype.removeMany = DOMTokenList.prototype.removeMany || function(classes) {...}
      

      【讨论】:

      • 仍然是一个很好的答案。我无法为你编辑它,因为它只有 2 个字符。
      【解决方案5】:

      由于来自classListadd() 方法只允许传递单独的参数而不是单个数组,因此您需要使用apply 调用add()。对于第一个参数,您需要从同一个 DOM 节点传递 classList 引用,第二个参数是您要添加的类数组:

      element.classList.add.apply(
        element.classList,
        ['class-0', 'class-1', 'class-2']
      );
      

      【讨论】:

      【解决方案6】:

      这是一个针对 IE 10 和 11 用户的解决方法,看起来非常简单。

      var elem = document.getElementById('elem');
      
      ['first','second','third'].forEach(item => elem.classList.add(item));
      &lt;div id="elem"&gt;Hello World!&lt;/div&gt;

      或者

      var elem = document.getElementById('elem'),
          classes = ['first','second','third'];
      
      classes.forEach(function(item) {
          elem.classList.add(item);
      });
      &lt;div id="elem"&gt;Hello World!&lt;/div&gt;

      【讨论】:

      • 好主意。不过,我会使用 .forEach() 而不是 .map() - 对于像这种不使用返回数组的情况,它更清洁/更有效。
      • 是的,没错。
      【解决方案7】:

      为元素添加类

      document.querySelector(elem).className+=' first second third';
      

      更新:

      删除一个类

      document.querySelector(elem).className=document.querySelector(elem).className.split(class_to_be_removed).join(" ");
      

      【讨论】:

      • 这很有趣,但它所做的只是编辑类的字符串。如果我想删除几个类,它就行不通了。抱歉,我忘记在 OP 中添加了。
      • 不要使用className。这对性能来说很糟糕(即使检索它的值也会导致回流)。
      【解决方案8】:

      较新版本的DOMTokenList spec 允许add()remove() 的多个参数,以及toggle() 的第二个参数来强制状态。

      在撰写本文时,Chrome 支持 add()remove() 的多个参数,但其他浏览器都不支持。 IE 10 及更低版本、Firefox 23 及更低版本、Chrome 23 及更低版本等浏览器不支持toggle() 的第二个参数。

      我编写了以下小型 polyfill 来帮助我渡过难关,直到支持扩展:

      (function () {
          /*global DOMTokenList */
          var dummy  = document.createElement('div'),
              dtp    = DOMTokenList.prototype,
              toggle = dtp.toggle,
              add    = dtp.add,
              rem    = dtp.remove;
      
          dummy.classList.add('class1', 'class2');
      
          // Older versions of the HTMLElement.classList spec didn't allow multiple
          // arguments, easy to test for
          if (!dummy.classList.contains('class2')) {
              dtp.add    = function () {
                  Array.prototype.forEach.call(arguments, add.bind(this));
              };
              dtp.remove = function () {
                  Array.prototype.forEach.call(arguments, rem.bind(this));
              };
          }
      
          // Older versions of the spec didn't have a forcedState argument for
          // `toggle` either, test by checking the return value after forcing
          if (!dummy.classList.toggle('class1', true)) {
              dtp.toggle = function (cls, forcedState) {
                  if (forcedState === undefined)
                      return toggle.call(this, cls);
      
                  (forcedState ? add : rem).call(this, cls);
                  return !!forcedState;
              };
          }
      })();
      

      一个符合 ES5 和 DOMTokenList 的现代浏览器是预期的,但我在几个专门针对的环境中使用这个 polyfill,所以它对我来说非常有用,但它可能需要对将在旧浏览器环境中运行的脚本进行调整例如 IE 8 及更低版本。

      【讨论】:

      • 似乎没有人提到 IE10 不允许添加多个类。这对我很有效,所以谢谢!尽管在 IE9 中我收到一个错误,即 DomTokenList 未定义,但我会警告。您可能也想考虑这一点。或者只运行这个 if( typeof DomTokenList !== 'undefined')
      • @Ryan:谢谢,我认为 DOMTokenList 在 IE 9 中是受支持的,但我想它被遗漏了。我会在某个时候尝试调查解决方法。
      • 看起来在失败的 DOMTokenList 上,您必须将 className 与单词边界 regEx 检查一起使用
      【解决方案9】:

      我不得不相信一个非常简单、不花哨但可行的解决方案是跨浏览器:

      创建这个函数

      function removeAddClasses(classList,removeCollection,addCollection){
          for (var i=0;i<removeCollection.length;i++){ 
              classList.remove(removeCollection[i]); 
          }
          for (var i=0;i<addCollection.length;i++){ 
              classList.add(addCollection[i]); 
          }
      }

      这样称呼它: removeAddClasses(node.classList,arrayToRemove,arrayToAdd);

      ...其中 arrayToRemove 是要删除的类名数组: ['myClass1','myClass2'] 等等

      ...并且 arrayToAdd 是要添加的类名数组: ['myClass3','myClass4'] 等等

      【讨论】:

        【解决方案10】:

        标准定义只允许添加或删除单个类。几个小的包装函数可以满足你的要求:

        function addClasses (el, classes) {
          classes = Array.prototype.slice.call (arguments, 1);
          console.log (classes);
          for (var i = classes.length; i--;) {
            classes[i] = classes[i].trim ().split (/\s*,\s*|\s+/);
            for (var j = classes[i].length; j--;)
              el.classList.add (classes[i][j]);
          }
        }
        
        function removeClasses (el, classes) {
          classes = Array.prototype.slice.call (arguments, 1);
          for (var i = classes.length; i--;) {
            classes[i] = classes[i].trim ().split (/\s*,\s*|\s+/);
            for (var j = classes[i].length; j--;)
              el.classList.remove (classes[i][j]);
          }
        }
        

        这些包装器允许您将类列表指定为单独的参数、带有空格或逗号分隔项的字符串或组合。示例见http://jsfiddle.net/jstoolsmith/eCqy7

        【讨论】:

          【解决方案11】:

          假设你有一个类数组要添加,你可以使用 ES6 扩展语法:

          let classes = ['first', 'second', 'third']; elem.classList.add(...classes);

          【讨论】:

            【解决方案12】:

            在字符串中添加由空格分隔的多个类的更好方法是使用Spread_syntaxsplit

            element.classList.add(...classesStr.split(" "));
            

            【讨论】:

              【解决方案13】:

              我喜欢@rich.kelly 的回答,但我想使用与classList.add() 相同的命名法(逗号分隔的字符串),所以略有偏差。

              DOMTokenList.prototype.addMany = DOMTokenList.prototype.addMany || function() {
                for (var i = 0; i < arguments.length; i++) {
                  this.add(arguments[i]);
                }
              }
              DOMTokenList.prototype.removeMany = DOMTokenList.prototype.removeMany || function() {
                for (var i = 0; i < arguments.length; i++) {
                  this.remove(arguments[i]);
                }
              }
              

              所以你可以使用:

              document.body.classList.addMany('class-one','class-two','class-three');
              

              我需要测试所有浏览器,但这适用于 Chrome。
              我们是否应该检查比DOMTokenList.prototype.addMany 的存在更具体的东西?究竟是什么导致classList.add() 在 IE11 中失败?

              【讨论】:

                【解决方案14】:

                element.classList 的另一个 polyfill 是 here。我是通过MDN找到的。

                我包含该脚本并按预期使用element.classList.add("first","second","third")

                【讨论】:

                  【解决方案15】:

                  我找到了一个非常简单的方法,它更现代、更优雅。

                  
                  const el = document.querySelector('.m-element');
                  
                  // To toggle
                  ['class1', 'class2'].map((e) => el.classList.toggle(e));
                  
                  // To add
                  ['class1', 'class2'].map((e) => el.classList.add(e));
                  
                  // To remove
                  ['class1', 'class2'].map((e) => el.classList.remove(e));
                  
                  

                  好在你可以扩展类数组或轻松使用任何来自 API 的数组。

                  【讨论】:

                    【解决方案16】:

                    最佳解决方案之一是检查元素是否存在,然后继续添加或删除,最重要的是如果元素为空删除它。

                    /**
                     * @description detect if obj is an element
                     * @param {*} obj
                     * @returns {Boolean}
                     * @example
                     * see below
                     */
                    function isElement(obj) {
                      if (typeof obj !== 'object') {
                        return false
                      }
                      let prototypeStr, prototype
                      do {
                        prototype = Object.getPrototypeOf(obj)
                        // to work in iframe
                        prototypeStr = Object.prototype.toString.call(prototype)
                        // '[object Document]' is used to detect document
                        if (
                          prototypeStr === '[object Element]' ||
                          prototypeStr === '[object Document]'
                        ) {
                          return true
                        }
                        obj = prototype
                        // null is the terminal of object
                      } while (prototype !== null)
                        return false
                    }
                    
                    /*
                     * Add multiple class
                     * addClasses(element,['class1','class2','class3'])
                     * el: element | document.querySelector(".mydiv");
                     * classes: passing:: array or string : [] | 'cl1,cl2' | 'cl1 cl2' | 'cl1|cl2'
                     */
                    function addClasses(el, classes) {
                      classes = Array.prototype.slice.call(arguments, 1);
                      if ( isElement(el) ){ //if (document.body.contains(el)
                        for (var i = classes.length; i--;) {
                          classes[i] = Array.isArray(classes[i]) ? classes[i]: classes[i].trim().split(/\s*,\s*|\s+/);
                          for (var j = classes[i].length; j--;)
                            el.classList.add(classes[i][j]);
                        }
                      }
                    }
                    
                    /*
                     * Remove multiple class
                     * Remove attribute class is empty
                     * addClasses(element,['class1','class2','class3'])
                     * el: element | document.querySelector(".mydiv");
                     * classes: passing:: array or string : [] | 'cl1,cl2' | 'cl1 cl2' | 'cl1|cl2'
                     */
                    function removeClasses(el, classes) {
                      classes = Array.prototype.slice.call(arguments, 1);
                      if ( isElement(el) ) {
                        for (var i = classes.length; i--;) {
                          classes[i] = Array.isArray(classes[i]) ? classes[i]: classes[i].trim().split(/\s*,\s*|\s+/);
                          for (var j = classes[i].length; j--;)
                            el.classList.remove(classes[i][j]);
                            let cl = el.className.trim();
                            if (!cl){
                              el.removeAttribute('class');
                            }
                        }
                      }
                    }
                    
                    var div = document.createElement("div");
                    div.id = 'test'; // div.setAttribute("id", "test");
                    div.textContent = 'The World';
                    //div.className = 'class';
                    // possible use: afterend, beforeend
                    document.body.insertAdjacentElement('beforeend', div); 
                    
                    // Everything written above you can do so:
                    //document.body.insertAdjacentHTML('beforeend', '<div id="text"></div>');
                    
                    var el = document.querySelector("#test");
                    addClasses(el,'one,two,three,four');
                    removeClasses(el,'two,two,never,other');
                    el.innerHTML = 'I found: '+el.className;
                    // return : I found: four three one
                    #test {
                      display: inline-block;
                      border: 1px solid silver;
                      padding: 10px;
                    }

                    【讨论】:

                      猜你喜欢
                      • 2019-09-09
                      • 2019-04-26
                      • 2022-01-20
                      • 2018-04-21
                      • 1970-01-01
                      • 2021-10-08
                      • 1970-01-01
                      • 2011-10-10
                      • 2021-03-30
                      相关资源
                      最近更新 更多