Як додати / видалити клас у JavaScript?


75

Оскільки element.classListне підтримується в IE 9 та Safari-5, яке альтернативне рішення між браузерами?

Без фреймворків, будь ласка.

Рішення має працювати принаймні в IE 9 , Safari 5 , FireFox 4, Opera 11.5 та Chrome.

Пов’язані повідомлення (але не містить рішення):

  1. як додати та видалити клас css -

  2. Додавання та видалення класу з анімацією

  3. Додати клас видалення?


6
Я ніколи не зрозумію необхідності коду, сумісного з переглядачами, та відмови використовувати фреймворк. Це їхнє саме призначення. Це все одно, що намагатися з’їсти спагетті, але відмовитися від використання виделки, впевнений, що ви можете обійтись, але це брудно.
davin

2
@davin існує різниця між фреймворками та прокладками. Прокладки також дійсні.
Raynos

1
@Raynos, більшу частину того, що ти думаєш, буде лише однією фішкою, закінчується п’ятьма, що призводить до набагато менш ремонтопридатного, менш перевіреного коду, який краще замінити фреймворком.
davin

4
@davin Вам потрібен лише один підклад. Це називається прокладкою DOM. Тоді ви просто пишете код, що відповідає стандартам. Вам потрібен фреймворк, він називається DOM.
Raynos

24
@davin, тому що їсти спагетті виделкою не означає, що вам не дозволено розуміти, як працює виделка.
Pacerier

Відповіді:


15

Одним із способів пограти з класами без фреймворків / бібліотек було б використання властивості Element.className, яке " отримує та встановлює значення атрибута класу вказаного елемента. " (З документації MDN ).
Як @ matías-fidemraizer вже згадано у своїй відповіді, як тільки ви отримаєте рядок класів для вашого елемента, ви можете використовувати будь-які методи, пов'язані з рядками, щоб змінити його.

Ось приклад: якщо
припустити, що у вас є div з ідентифікатором "myDiv" і що ви хочете додати до нього клас "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
}

11
Як це може бути прийнятою відповіддю, тоді питання включає клас "видалити", але ця відповідь ні?
Мотін,

7
.replace (/ \ bexmaple \ b /, "")
leafiy

це не працює для елемента svg, створеного за допомогою "createElementNS". Як це можна досягти?
neoexpert

62

Ось рішення для addClass, removeClass, hasClass у чистому розчині javascript.

Насправді це з 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,' ');
  }
}

33

Я щойно написав це:

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.
Пол

6
Це не спрацює. Якщо елемент має клас 'abc', і ви намагаєтесь видалити b, він встановить для нового класу значення 'ac'. Таким чином , ви повинні змінити з ''допомогою ' 'в replaceфункції. Більше того, клас - це зарезервоване ключове слово.
Балі Бало

1
Я зафіксував ваше рішення на 1. Не використовуйте "клас", що є зарезервованим словом 2. Ваш непрацюючий removeClassметод, який створює безліч безладу після багаторазового використання через те, що пробіли не обрізані. Див. Рішення нижче як відповідь.
Дрю

Я використав цей код із додаванням цього коду відразу після заяви заміна: while (elClass[0] === " ") elClass = elClass.substr(1); while (elClass[elClass.length - 1] === " ") elClass = elClass.substr(0, elClass.length - 1);Це видалить провідний та кінцевий пробіл, який все ще може бути присутнім
Філіп Корнеліссен

25

Подивіться на ці лайнери:

  1. Вилучити клас:

    element.classList.remove('hidden');
    
  2. Переключити клас (додає клас, якщо він ще не присутній, і видаляє, якщо він є)

    element.classList.toggle('hidden');
    

Це все! Я зробив тест - 10000 ітерацій. 0,8 с.


Зверніть увагу, що classList не підтримується в IE 9, про що йдеться у запитанні OP
Уоррен Спенсер

2
хоча воно не задовольняє обмеження, яке було надзвичайно характерним для ОП, я думаю, це питання розглядається багатьма людьми, які сподіваються отримати відповідь на загальне питання без цих конкретних обмежень. Я був дуже радий знайти це, і помітив це лише під час свого другого візиту. Я радий, що зробив - набагато чистіше рішення. Дякую!
Кайл Бейкер

18

Найпростіший , element.classListякий має remove(name), add(name), toggle(name)і contains(name)методи , і в даний час підтримується всіма основними браузерами .

Для старих браузерів ви змінюєтесь element.className. Ось два помічники:

function addClass(element, className){
    element.className += ' ' + className;   
}

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

це не працює для елемента svg, створеного за допомогою "createElementNS". Як це можна досягти?
neoexpert

10

Прочитайте цю статтю мережі розробників Mozilla:

Оскільки властивість element.className має тип string, ви можете використовувати звичайні функції об’єкта String, знайдені в будь-якій реалізації JavaScript:

  • Якщо ви хочете додати клас, спочатку використовуйте String.indexOf, щоб перевірити, чи присутній клас у className . Якщо його немає, просто об’єднайте порожній символ та нове ім’я класу в цю властивість. Якщо він присутній, нічого не робіть.

  • Якщо ви хочете видалити клас, просто використовуйте String.replace, замінивши "[className]" порожнім рядком. Нарешті, використовуйте String.trimдля видалення порожніх символів на початку та в кінці element.className.


5

Виправлено рішення від @Paulpro

  1. Не використовуйте "клас", оскільки це зарезервоване слово
  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;
}

Хіба ви не могли перевірити, чи існує ім'я класу, перш ніж додавати його?
JoeTidee

if(el.className.indexOf(' ' + className) != -1) return;to addClasswould help
keaton

4

Рішення полягає в

Шим .classList:

Або використовуйте DOM-прокладку, або використовуйте прокладку 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));

}

1
Безумовно, розумний шим. Він працює у FF принаймні до 1,5 (не можна перевірити нижче цього). Це порушує IE7 і нижче. З цієї причини на реальних сайтах він майже марний для чогось важливого. Для реального використання використовуйте фреймворк.
theazureshadow

@theazureshadow psh, Підтримка Legacy призначена для корпоративних рішень, які піклуються про IE7 за межами корпоративного світу.
Райнос,

Якщо ви піклуєтесь про 12 відсотків користувачів (приблизно кожного восьмого), які зараз використовують IE7 і нижче (джерело: marketshare.hitslink.com ). Я думаю, що iOS 5 є першою версією iOS, яка також її підтримує, тому на момент публікації жоден користувач iPhone не підтримувався. Розмова про спадщину!
theazureshadow

1
@theazureshadow meh, IE7 не потребує JavaScript. А мобільні - це зовсім інша гра з м’ячем. (Прокладка повинна працювати на мобільних телефонах)
Райнос,

Ви маєте рацію щодо мобільних пристроїв. Чи справді підтримка IE7 дійсно залежить від окремих випадків. Більшості людей буде легко варто використовувати фреймворк для згладжування відмінностей браузера - далеко поза межами доступності classList. "IE7 не потребує JavaScript" - надзвичайно сумнівне твердження.
theazureshadow

3

Покращена версія коду Еміля (з 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();
  }
}

2
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(' ');
}

2

Про всяк випадок, якщо хтось хотів би мати прототипи, побудовані для елементів, це те, що я використовую, коли мені потрібно маніпулювати класами різних об'єктів:

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, ви його називаєте)


0

додати класи css: cssClassesStr += cssClassName;

видалити css-класи: cssClassStr = cssClassStr.replace(cssClassName,"");

додати атрибут "Класи": object.setAttribute("class", ""); //pure addition of this attribute

видалити атрибут: object.removeAttribute("class");


0

Легкий для розуміння спосіб:

// 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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.