【问题标题】:How to add/remove a class in JavaScript?如何在 JavaScript 中添加/删除类?
【发布时间】:2011-10-10 20:54:21
【问题描述】:

由于 IE 9 和 Safari-5 不支持 element.classList,有什么替代的跨浏览器解决方案?

No-frameworks 请。

解决方案必须至少在 IE 9Safari 5、FireFox 4、Opera 11.5 和 Chrome 中工作。

相关帖子(但不包含解决方案):

  1. how to add and remove css class

  2. Add and remove a class with animation

  3. Add remove class?

【问题讨论】:

  • 我永远不会理解跨浏览器兼容代码的需求以及拒绝使用框架的必要性。这就是他们的目的。这就像想吃意大利面但拒绝使用叉子,当然可以过,但很乱。
  • @davin 框架和垫片之间是有区别的。垫片也是有效的。
  • @Raynos,大多数情况下,您认为只有一个 shim 的东西最终变成了五个,这会导致可维护性、测试更少的代码,最好用框架代替。
  • @davin 你只需要一个垫片。它被称为 DOM 垫片。然后,您只需编写符合标准的代码。你确实需要一个框架,它叫做 DOM。
  • @davin 因为用叉子吃意大利面并不意味着你不能理解叉子的工作原理。

标签: javascript dom cross-browser


【解决方案1】:

阅读这篇 Mozilla 开发者网络文章:

由于 element.className 属性是字符串类型,您可以使用任何 JavaScript 实现中的常规字符串对象函数:

  • 如果你想添加一个类,首先使用String.indexOf 来检查类是否存在于className中。如果它不存在,只需将一个空白字符和新类名连接到此属性。如果存在,什么也不做。

  • 如果你想删除一个类,只需使用String.replace,将“[className]”替换为一个空字符串。最后用String.trim去掉element.className开头和结尾的空白字符。

【讨论】:

    【解决方案2】:

    添加 css 类:cssClassesStr += cssClassName;

    删除 css 类:cssClassStr = cssClassStr.replace(cssClassName,"");

    添加属性“类”:object.setAttribute("class", ""); //pure addition of this attribute

    删除属性:object.removeAttribute("class");

    【讨论】:

      【解决方案3】:

      我刚刚写了这些:

      function addClass(el, classNameToAdd){
          el.className += ' ' + classNameToAdd;   
      }
      
      function removeClass(el, classNameToRemove){
          var elClass = ' ' + el.className + ' ';
          while(elClass.indexOf(' ' + classNameToRemove + ' ') !== -1){
               elClass = elClass.replace(' ' + classNameToRemove + ' ', '');
          }
          el.className = elClass;
      }
      

      我认为它们适用于所有浏览器。

      【讨论】:

      • 这不起作用,例如,如果您尝试删除元素上的唯一类(其名称两侧都没有空格)
      • @Gareth,这行得通。它在 removeClass 的第一行的每一侧插入一个空格。
      • 那行不通。如果元素具有类“a b c”并且您尝试删除 b,它会将新类设置为“ac”。因此,您必须在 replace 函数中将 '' 更改为 ' '。此外,class 是保留关键字。
      • 我已将您的解决方案修复为 1. 不使用“class”,这是一个保留字 2. 您损坏的 removeClass 方法,由于没有空格,在重复使用后会产生大量混乱修剪请参阅下面的解决方案作为答案。
      • 我使用了这段代码,并在替换语句之后添加了这段代码:while (elClass[0] === " ") elClass = elClass.substr(1); while (elClass[elClass.length - 1] === " ") elClass = elClass.substr(0, elClass.length - 1); 这将删除可能仍然存在的前导和尾随空格
      【解决方案4】:

      解决办法是

      Shim .classList:

      使用DOM-shim 或使用下面的 Eli Grey 垫片

      免责声明:相信支持的是FF3.6+、Opera10+、FF5、Chrome、IE8+

      /*
       * classList.js: Cross-browser full element.classList implementation.
       * 2011-06-15
       *
       * By Eli Grey, http://eligrey.com
       * Public Domain.
       * NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
       */
      
      /*global self, document, DOMException */
      
      /*! @source http://purl.eligrey.com/github/classList.js/blob/master/classList.js*/
      
      if (typeof document !== "undefined" && !("classList" in document.createElement("a"))) {
      
      (function (view) {
      
      "use strict";
      
      var
            classListProp = "classList"
          , protoProp = "prototype"
          , elemCtrProto = (view.HTMLElement || view.Element)[protoProp]
          , objCtr = Object
          , strTrim = String[protoProp].trim || function () {
              return this.replace(/^\s+|\s+$/g, "");
          }
          , arrIndexOf = Array[protoProp].indexOf || function (item) {
              var
                    i = 0
                  , len = this.length
              ;
              for (; i < len; i++) {
                  if (i in this && this[i] === item) {
                      return i;
                  }
              }
              return -1;
          }
          // Vendors: please allow content code to instantiate DOMExceptions
          , DOMEx = function (type, message) {
              this.name = type;
              this.code = DOMException[type];
              this.message = message;
          }
          , checkTokenAndGetIndex = function (classList, token) {
              if (token === "") {
                  throw new DOMEx(
                        "SYNTAX_ERR"
                      , "An invalid or illegal string was specified"
                  );
              }
              if (/\s/.test(token)) {
                  throw new DOMEx(
                        "INVALID_CHARACTER_ERR"
                      , "String contains an invalid character"
                  );
              }
              return arrIndexOf.call(classList, token);
          }
          , ClassList = function (elem) {
              var
                    trimmedClasses = strTrim.call(elem.className)
                  , classes = trimmedClasses ? trimmedClasses.split(/\s+/) : []
                  , i = 0
                  , len = classes.length
              ;
              for (; i < len; i++) {
                  this.push(classes[i]);
              }
              this._updateClassName = function () {
                  elem.className = this.toString();
              };
          }
          , classListProto = ClassList[protoProp] = []
          , classListGetter = function () {
              return new ClassList(this);
          }
      ;
      // Most DOMException implementations don't allow calling DOMException's toString()
      // on non-DOMExceptions. Error's toString() is sufficient here.
      DOMEx[protoProp] = Error[protoProp];
      classListProto.item = function (i) {
          return this[i] || null;
      };
      classListProto.contains = function (token) {
          token += "";
          return checkTokenAndGetIndex(this, token) !== -1;
      };
      classListProto.add = function (token) {
          token += "";
          if (checkTokenAndGetIndex(this, token) === -1) {
              this.push(token);
              this._updateClassName();
          }
      };
      classListProto.remove = function (token) {
          token += "";
          var index = checkTokenAndGetIndex(this, token);
          if (index !== -1) {
              this.splice(index, 1);
              this._updateClassName();
          }
      };
      classListProto.toggle = function (token) {
          token += "";
          if (checkTokenAndGetIndex(this, token) === -1) {
              this.add(token);
          } else {
              this.remove(token);
          }
      };
      classListProto.toString = function () {
          return this.join(" ");
      };
      
      if (objCtr.defineProperty) {
          var classListPropDesc = {
                get: classListGetter
              , enumerable: true
              , configurable: true
          };
          try {
              objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
          } catch (ex) { // IE 8 doesn't support enumerable:true
              if (ex.number === -0x7FF5EC54) {
                  classListPropDesc.enumerable = false;
                  objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
              }
          }
      } else if (objCtr[protoProp].__defineGetter__) {
          elemCtrProto.__defineGetter__(classListProp, classListGetter);
      }
      
      }(self));
      
      }
      

      【讨论】:

      • 绝对是一个聪明的垫片。它在 FF 中至少可以工作到 1.5(不能低于该值进行测试)。它在 IE7 及以下版本中中断。出于这个原因,对于任何必要的东西,它在真实网站上几乎没有用处。要真正使用,请使用框架。
      • @theazureshadow psh,旧版支持适用于企业解决方案,他们关心企业世界之外的 IE7。
      • 如果您关心目前使用 IE7 及以下版本的 12% 的用户(大约八分之一)(来源:marketshare.hitslink.com)。我认为 iOS 5 也是第一个支持它的 iOS 版本,所以在你发帖时没有任何 iPhone 用户会受到支持。谈论遗产!
      • @theazureshadow meh,IE7 不需要 javascript。手机是完全不同的球类游戏。 (垫片应该在手机上工作)
      • 您对移动设备的看法是正确的。是否值得支持 IE7 取决于具体情况。大多数人会发现使用框架来消除浏览器差异很值得——远远超出了 classList 的可用性。 “IE7 不需要 javascript”是一个非常有问题的说法。
      【解决方案5】:

      修复了来自@Paulpro 的解决方案

      1. 不要使用“class”,因为它是保留字
      2. removeClass函数 坏了,因为它在反复使用后就坏了。

      `

      function addClass(el, newClassName){
          el.className += ' ' + newClassName;   
      }
      
      function removeClass(el, removeClassName){
          var elClass = el.className;
          while(elClass.indexOf(removeClassName) != -1) {
              elClass = elClass.replace(removeClassName, '');
              elClass = elClass.trim();
          }
          el.className = elClass;
      }
      

      【讨论】:

      • 您不应该在添加之前检查类名是否存在吗?
      • if(el.className.indexOf(' ' + className) != -1) return;addClass 会有所帮助
      【解决方案6】:

      最简单的是element.classList,它有remove(name)add(name)toggle(name)contains(name)方法,现在是supported by all major browsers

      对于旧版浏览器,您更改element.className。这里有两个助手:

      function addClass(element, className){
          element.className += ' ' + className;   
      }
      
      function removeClass(element, className) {
          element.className = element.className.replace(
              new RegExp('( |^)' + className + '( |$)', 'g'), ' ').trim();
      }
      

      【讨论】:

      • 这不适用于使用“createElementNS”创建的 svg 元素。如何做到这一点?
      【解决方案7】:

      在没有框架/库的情况下使用类的一种方法是使用属性 Element.className,它“获取并设置指定元素的类属性的值。”(来自MDN documentation)。
      正如@matías-fidemraizer 在他的回答中已经提到的那样,一旦您获得了元素的类字符串,您就可以使用与字符串关联的任何方法来修改它。

      这是一个例子:
      假设您有一个 ID 为“myDiv”的 div,并且您希望在用户单击它时向其添加类“main__section”,

      window.onload = init;
      
      function init() {
        document.getElementById("myDiv").onclick = addMyClass;
      }
      
      function addMyClass() {
        var classString = this.className; // returns the string of all the classes for myDiv
        var newClass = classString.concat(" main__section"); // Adds the class "main__section" to the string (notice the leading space)
        this.className = newClass; // sets className to the new string
      }
      

      【讨论】:

      • 这怎么可能是公认的答案,那么问题包括“删除”类但这个答案不是?
      • .replace(/\bexmaple\b/, "")
      • 这不适用于使用“createElementNS”创建的 svg 元素。如何做到这一点?
      【解决方案8】:

      这里是纯javascript解决方案中addClass、removeClass、hasClass的解决方案。

      其实是来自http://jaketrent.com/post/addremove-classes-raw-javascript/

      function hasClass(ele,cls) {
        return !!ele.className.match(new RegExp('(\\s|^)'+cls+'(\\s|$)'));
      }
      
      function addClass(ele,cls) {
        if (!hasClass(ele,cls)) ele.className += " "+cls;
      }
      
      function removeClass(ele,cls) {
        if (hasClass(ele,cls)) {
          var reg = new RegExp('(\\s|^)'+cls+'(\\s|$)');
          ele.className=ele.className.replace(reg,' ');
        }
      }
      

      【讨论】:

        【解决方案9】:

        emil 代码的改进版(带有 trim())

        function hasClass(ele,cls) {
          return !!ele.className.match(new RegExp('(\\s|^)'+cls+'(\\s|$)'));
        }
        
        function addClass(ele,cls) {
          if (!hasClass(ele,cls)) ele.className = ele.className.trim() + " " + cls;
        }
        
        function removeClass(ele,cls) {
          if (hasClass(ele,cls)) {
            var reg = new RegExp('(\\s|^)'+cls+'(\\s|$)');
            ele.className = ele.className.replace(reg,' ');
            ele.className = ele.className.trim();
          }
        }
        

        【讨论】:

          【解决方案10】:

          看看这些oneliners:

          1. 删除类:

            element.classList.remove('hidden');
            
          2. 切换类(如果该类尚不存在则添加该类,如果存在则将其删除)

            element.classList.toggle('hidden');
            

          就是这样!我做了一个测试 - 10000 次迭代。 0.8 秒。

          【讨论】:

          • 请注意,IE 9 中不支持 classList,这在 OP 的问题中有所说明
          • 虽然它不满足对 OP 极为特殊的限制,但我认为许多人都会关注这个问题,希望在没有这些特定限制的情况下回答一般问题。我很高兴找到这个,并且在我第二次访问时才注意到它。我很高兴我做到了——更清洁的解决方案。谢谢!
          【解决方案11】:
          function addClass(element, classString) {
              element.className = element
                  .className
                  .split(' ')
                  .filter(function (name) { return name !== classString; })
                  .concat(classString)
                  .join(' ');
          }
          
          function removeClass(element, classString) {
              element.className = element
                  .className
                  .split(' ')
                  .filter(function (name) { return name !== classString; })
                  .join(' ');
          }
          

          【讨论】:

            【解决方案12】:

            以防万一有人想为元素构建原型函数,这就是我需要操作不同对象的类时使用的方法:

            Element.prototype.addClass = function (classToAdd) {
              var classes = this.className.split(' ')
              if (classes.indexOf(classToAdd) === -1) classes.push(classToAdd)
              this.className = classes.join(' ')
            }
            
            Element.prototype.removeClass = function (classToRemove) {
              var classes = this.className.split(' ')
              var idx =classes.indexOf(classToRemove)
              if (idx !== -1) classes.splice(idx,1)
              this.className = classes.join(' ')
            }
            

            像这样使用它们: document.body.addClass('whatever')document.body.removeClass('whatever')

            除了body,你还可以使用任何其他元素(div、span,你可以命名)

            【讨论】:

              【解决方案13】:

              简单易懂的方式:

              // Add class 
              DOMElement.className += " one";
              // Example:
              // var el = document.body;
              // el.className += " two"
              
              // Remove class 
              function removeDOMClass(element, className) {
                  var oldClasses      = element.className,
                      oldClassesArray = oldClasses.split(" "),
                      newClassesArray = [],
                      newClasses;
              
                  // Sort
                  var currentClassChecked,
                      i;     
                  for ( i = 0; i < oldClassesArray.length; i++ ) { 
                      // Specified class will not be added in the new array
                      currentClassChecked = oldClassesArray[i];
                      if( currentClassChecked !== className ) { 
                          newClassesArray.push(currentClassChecked);
                      }
                  }
              
                  // Order 
                  newClasses = newClassesArray.join(" ");
              
                  // Apply     
                  element.className = newClasses;
              
                  return element;
              
              }
              // Example:
              // var el = document.body;
              // removeDOMClass(el, "two")
              

              https://gist.github.com/sorcamarian/ff8db48c4dbf4f5000982072611955a2

              【讨论】:

                猜你喜欢
                • 2015-09-16
                • 2023-03-07
                • 1970-01-01
                • 1970-01-01
                • 2021-07-14
                • 1970-01-01
                • 1970-01-01
                • 2014-10-01
                • 2018-11-13
                相关资源
                最近更新 更多