Проверить, содержит ли элемент класс?

Используя простой JavaScript (не jQuery), есть ли способ проверить, содержит ли элемент класс?

В настоящее время я делаю это:

HTML:

<div id="test" class="class1"></div>;

JS:

var test = document.getElementById("test");
var testClass = test.className;
switch(testClass){
    case "class1": test.innerHTML = "I have class1"; break;
    case "class2": test.innerHTML = "I have class2"; break;
    case "class3": test.innerHTML = "I have class3"; break;
    case "class4": test.innerHTML = "I have class4"; break;
    default: test.innerHTML = "";
}

Это приводит к этому выводу, который является правильным:

I have class1

Проблема в том, что если я изменю HTML на этот...

<div id="test" class="class1 class5"></div>

... точного соответствия больше нет, поэтому я получаю вывод по умолчанию ничего (""). Но я все еще хочу, чтобы результат был I have class1 поскольку <div> до сих пор содержит .class1 учебный класс.

30 ответов

Решение

Использование element.classList.contains метод:

element.classList.contains(class);

Это работает во всех текущих браузерах, и есть полифилы для поддержки старых браузеров.


В качестве альтернативы, если вы работаете со старыми браузерами и не хотите использовать полифиллы для их исправления, используйте indexOf это правильно, но вы должны немного подправить:

function hasClass(element, className) {
    return (' ' + element.className + ' ').indexOf(' ' + className+ ' ') > -1;
}

В противном случае вы также получите true если класс, который вы ищете, является частью другого имени класса.

DEMO

jQuery использует аналогичный (если не тот же) метод.


Применительно к примеру:

Поскольку это не работает вместе с оператором switch, вы можете добиться того же эффекта с помощью этого кода:

var test = document.getElementById("test"),
    classes = ['class1', 'class2', 'class3', 'class4'];

test.innerHTML = "";

for(var i = 0, j = classes.length; i < j; i++) {
    if(hasClass(test, classes[i])) {
        test.innerHTML = "I have " + classes[i];
        break;
    }
}

Это также менее избыточно;)

Простое и эффективное решение - метод .contains.

test.classList.contains(testClass);

В современных браузерах вы можете просто использовать contains метод Element.classList:

testElement.classList.contains(className)

демонстрация

var testElement = document.getElementById('test');

console.log({
    'main' : testElement.classList.contains('main'),
    'cont' : testElement.classList.contains('cont'),
    'content' : testElement.classList.contains('content'),
    'main-cont' : testElement.classList.contains('main-cont'),
    'main-content' : testElement.classList.contains('main-content')
});
<div id="test" class="main main-content content"></div>


Поддерживаемые браузеры

(от CanIUse.com)


Polyfill

Если вы хотите использовать Element.classList но вы также хотите поддерживать старые браузеры, подумайте об использовании этого полифилла от Eli Grey.

На этот вопрос довольно однозначно ответил element.classList.contains(), но люди стали довольно экстравагантными со своими ответами и сделали несколько смелых заявлений, поэтому я провел тест .

Помните, что каждый тест выполняет 1000 итераций, поэтому большинство из них все еще очень быстрые. Если вы не будете полностью полагаться на это для конкретной операции, вы не увидите разницы в производительности.

Я провел несколько тестов практически со всеми способами. На моей машине (Win 10, 24gb, i7-8700) classList.contains работал очень хорошо. То же самое и с className.split(''), которое фактически то же самое.

Хотя победитель classList.contains(). Если вы не проверяете, что classList undefined, ~(' ' + v.className + ' ').indexOf(' c' + i + ' ') ползет вперед 5-15%

Element.matches ()

element.matches (selectorString)

Согласно MDN Web Docs:

Element.matches() метод возвращает true если элемент будет выбран по указанной строке селектора; в противном случае возвращает false,

Поэтому вы можете использовать Element.matches() определить, содержит ли элемент класс.

const element = document.querySelector('#example');

console.log(element.matches('.foo')); // true
<div id="example" class="foo bar"></div>

View Browser Compatibility

Поскольку он хочет использовать switch(), я удивлен, что никто еще не высказал это:

var test = document.getElementById("test");
var testClasses = test.className.split(" ");
test.innerHTML = "";
for(var i=0; i<testClasses.length; i++) {
    switch(testClasses[i]) {
        case "class1": test.innerHTML += "I have class1<br/>"; break;
        case "class2": test.innerHTML += "I have class2<br/>"; break;
        case "class3": test.innerHTML += "I have class3<br/>"; break;
        case "class4": test.innerHTML += "I have class4<br/>"; break;
        default: test.innerHTML += "(unknown class:" + testClasses[i] + ")<br/>";
    }
}

Вот небольшой фрагмент кода. Если вы пытаетесь проверить, содержит ли элемент класс, без использования jQuery.

function hasClass(element, className) {
    return element.className && new RegExp("(^|\\s)" + className + "(\\s|$)").test(element.className);
}

Это объясняет тот факт, что элемент может содержать несколько имен классов, разделенных пробелом.

ИЛИ ЖЕ


Вы также можете назначить эту функцию прототипу элемента.

Element.prototype.hasClass = function(className) {
    return this.className && new RegExp("(^|\\s)" + className + "(\\s|$)").test(this.className);
};

И вызвать его так (очень похоже на JQuery.hasClass()функция):

document.getElementById('MyDiv').hasClass('active');

className это просто строка, поэтому вы можете использовать обычную функцию indexOf, чтобы увидеть, содержит ли список классов другую строку.

Это немного старый, но, возможно, кто-то найдет мое решение полезным:

// Fix IE's indexOf Array
if (!Array.prototype.indexOf) {
    Array.prototype.indexOf = function (searchElement) {
        if (this == null) throw new TypeError();
        var t = Object(this);
        var len = t.length >>> 0;
        if (len === 0) return -1;
        var n = 0;
        if (arguments.length > 0) {
            n = Number(arguments[1]);
            if (n != n) n = 0;
            else if (n != 0 && n != Infinity && n != -Infinity) n = (n > 0 || -1) * Math.floor(Math.abs(n));
        }
        if (n >= len) return -1;
        var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
        for (; k < len; k++) if (k in t && t[k] === searchElement) return k;
        return -1;
    }
}
// add hasClass support
if (!Element.prototype.hasClass) {
    Element.prototype.hasClass = function (classname) {
        if (this == null) throw new TypeError();
        return this.className.split(' ').indexOf(classname) === -1 ? false : true;
    }
}

Упрощенный oneliner:1

function hasClassName(classname,id) {
 return  String ( ( document.getElementById(id)||{} ) .className )
         .split(/\s/)
         .indexOf(classname) >= 0;
}

1 indexOf для массивов не поддерживается IE (ofcourse). Для этого в сети можно найти множество патчей обезьян.

Я знаю там много ответов, но большинство из них для дополнительных функций и дополнительных классов. Это тот, который я лично использую; намного чище и намного меньше строк кода!

if( document.body.className.match('category-page') ) { 
  console.log('yes');
}

Чтобы проверить, содержит ли элемент класс, вы используете метод contains () свойства classList элемента:*

      element.classList.contains(className);

* Предположим, у вас есть следующий элемент:

      <div class="secondary info">Item</div>*

Чтобы проверить, содержит ли элемент вторичный класс, вы используете следующий код:

       const div = document.querySelector('div');
 div.classList.contains('secondary'); // true

Следующее возвращает false, потому что элемент не имеет ошибки класса:

       const div = document.querySelector('div');
 div.classList.contains('error'); // false

Я создал метод-прототип, который использует classList, если возможно, еще прибегает к indexOf:

Element.prototype.hasClass = Element.prototype.hasClass || 
  function(classArr){
    var hasClass = 0,
        className = this.getAttribute('class');
  
    if( this == null || !classArr || !className ) return false;
  
    if( !(classArr instanceof Array) )
      classArr = classArr.split(' ');

    for( var i in classArr )
      // this.classList.contains(classArr[i]) // for modern browsers
      if( className.split(classArr[i]).length > 1 )  
          hasClass++;

    return hasClass == classArr.length;
};


///////////////////////////////
// TESTS (see browser's console when inspecting the output)

var elm1 = document.querySelector('p');
var elm2 = document.querySelector('b');
var elm3 = elm1.firstChild; // textNode
var elm4 = document.querySelector('text'); // SVG text

console.log( elm1, ' has class "a": ', elm1.hasClass('a') );
console.log( elm1, ' has class "b": ', elm1.hasClass('b') );
console.log( elm1, ' has class "c": ', elm1.hasClass('c') );
console.log( elm1, ' has class "d": ', elm1.hasClass('d') );
console.log( elm1, ' has class "a c": ', elm1.hasClass('a c') );
console.log( elm1, ' has class "a d": ', elm1.hasClass('a d') );
console.log( elm1, ' has class "": ', elm1.hasClass('') );

console.log( elm2, ' has class "a": ', elm2.hasClass('a') );

// console.log( elm3, ' has class "a": ', elm3.hasClass('a') );

console.log( elm4, ' has class "a": ', elm4.hasClass('a') );
<p class='a b c'>This is a <b>test</b> string</p>
<svg xmlns="http://www.w3.org/2000/svg" width="100px" height="50px">
    <text x="10" y="20" class='a'>SVG Text Example</text>
</svg>

Тестовая страница

Если элемент имеет только одно имя класса, вы можете быстро проверить его, получив атрибут класса. Другие ответы гораздо более надежны, но это, безусловно, имеет свои варианты использования.

if ( element.getAttribute('class') === 'classname' ) {

}

Посмотрите эту ссылку Codepen для более быстрого и простого способа проверки элемента, если у него есть определенный класс, использующий ванильный JavaScript ~!

hasClass (Vanilla JS)

function hasClass(element, cls) {
    return (' ' + element.className + ' ').indexOf(' ' + cls + ' ') > -1;
}
  1. Уловка Феликса, заключающаяся в добавлении пробелов по сторонам className и искомой строки, является правильным подходом к определению, имеет ли элемент класс или нет.

  2. Чтобы иметь различное поведение в зависимости от класса, вы можете использовать ссылки на функции или функции в карте:

    function fn1(element){ /* code for element with class1 */ }
    
    function fn2(element){ /* code for element with class2 */ }
    
    function fn2(element){ /* code for element with class3 */ }
    
    var fns={'class1': fn1, 'class2': fn2, 'class3': fn3};
    
    for(var i in fns) {
        if(hasClass(test, i)) {
            fns[i](test);
        }
    }
    
    • for (var i in fns) перебирает ключи в карте fns.
    • Отсутствие разрыва после fnsi позволяет коду выполняться всякий раз, когда есть совпадение, так что, если элемент имеет, fi, class1 и class2, будут выполняться как fn1, так и fn2.
    • Преимущество этого подхода состоит в том, что код, который нужно выполнить для каждого класса, является произвольным, как тот, который содержится в операторе switch; в вашем примере во всех случаях выполнялась аналогичная операция, но завтра вам может потребоваться выполнить разные действия для каждого из них.
    • Вы можете смоделировать случай по умолчанию, имея переменную состояния, сообщающую, найдено ли совпадение в цикле или нет.

Я бы заполнил Поли функциональностью classList и использовал бы новый синтаксис. Таким образом, более новый браузер будет использовать новую реализацию (что намного быстрее), и только старые браузеры получат снижение производительности из кода.

https://github.com/remy/polyfills/blob/master/classList.js

Это поддерживается в IE8+.

Сначала мы проверяем, если classList существует, если это так, мы можем использовать contains метод, который поддерживается IE10+. Если мы находимся на IE9 или 8, то возвращаемся к использованию регулярного выражения, которое не так эффективно, но является кратким полифилом.

if (el.classList)
  el.classList.contains(className);
else
  new RegExp('(^| )' + className + '( |$)', 'gi').test(el.className);

Вот не зависящее от регистра тривиальное решение:

function hasClass(element, classNameToTestFor) {
    var classNames = element.className.split(' ');
    for (var i = 0; i < classNames.length; i++) {
        if (classNames[i].toLowerCase() == classNameToTestFor.toLowerCase()) {
            return true;
        }
    }
    return false;
}

Я думаю, что идеальным решением будет это

if ($(this).hasClass("your_Class")) 
    alert("positive");            
else              
    alert("Negative");

Это немного не так, но если у вас есть событие, которое запускает переключение, вы можете обойтись без классов:

<div id="classOne1"></div>
<div id="classOne2"></div>
<div id="classTwo3"></div>

Ты можешь сделать

$('body').click( function() {

    switch ( this.id.replace(/[0-9]/g, '') ) {
        case 'classOne': this.innerHTML = "I have classOne"; break;
        case 'classTwo': this.innerHTML = "I have classTwo"; break;
        default: this.innerHTML = "";
    }

});

.replace(/[0-9]/g, '') удаляет цифры из id,

Это немного странно, но работает для длинных переключателей без дополнительных функций или петель

Использование classList также идеально

HTML

<div id="box" class="myClass"></div>

JavaScript

const element = document.querySelector("#box");

element.classList.contains("myClass");

Как следует из принятого ответа, Element.className возвращает строку, поэтому вы можете легко проверить, существует ли класс, используя indexOf() метод:

      element.className.indexOf('animated') > -1

Если вас интересует разница в производительности между vs classList.contains, с использованием indexOfвроде бы чуть быстрее. Чтобы проверить это, я провел быстрый тест производительности. Вот мои выводы: ClassName.indexOf vs ClassList.contains.

Просто чтобы добавить к ответу людей, пытающихся найти имена классов внутри встроенных элементов SVG.

Изменить hasCLass() функция для:

function hasClass(element, cls) {
    return (' ' + element.getAttribute('class') + ' ').indexOf(' ' + cls + ' ') > -1;
  }

Вместо использования className свойство, которое вам нужно будет использовать getAttribute() метод, чтобы захватить имя класса.

В каком элементе в настоящее время находится класс.bar? Вот еще одно решение, но оно зависит от вас.

var reg = /Image/g, // regexp for an image element
query = document.querySelector('.bar'); // returns [object HTMLImageElement]
query += this.toString(); // turns object into a string

if (query.match(reg)) { // checks if it matches
  alert('the class .bar is attached to the following Element:\n' + query);
}

демоверсия jsfiddle

Конечно, это только поиск для 1 простого элемента <img>(/Image/g) но вы можете поместить все в массив, как <li> является /LI/g, <ul> знак равно /UL/g и т.п.

Попробуй это:

document.getElementsByClassName = function(cl) {
   var retnode = [];
   var myclass = new RegExp('\\b'+cl+'\\b');
   var elem = this.getElementsByTagName('*');
   for (var i = 0; i < elem.length; i++) {
       var classes = elem[i].className;
       if (myclass.test(classes)) retnode.push(elem[i]);
   }
    return retnode;
};

Совет: постарайтесь как можно больше удалить зависимости jQuery в своих проектах - VanillaJS.

document.firstElementChild возвращается <html> пометьте затем classList атрибут возвращает все добавленные к нему классы.

if(document.firstElementChild.classList.contains("your-class")){
    // <html> has 'your-class'
} else {
    // <html> doesn't have 'your-class'
}

Эти функции я создал для своего сайта, использую только ванильный javascript, может, это кому-то поможет. Сначала я создал функцию для получения любого элемента HTML:

//return an HTML element by ID, class or tag name
    var getElement = function(selector) {
        var elements = [];
        if(selector[0] == '#') {
            elements.push(document.getElementById(selector.substring(1, selector.length)));
        } else if(selector[0] == '.') {
            elements = document.getElementsByClassName(selector.substring(1, selector.length));
        } else {
            elements = document.getElementsByTagName(selector);
        }
        return elements;
    }

Затем функция, которая получает класс для удаления и селектор элемента:

var hasClass = function(selector, _class) {
        var elements = getElement(selector);
        var contains = false;
        for (let index = 0; index < elements.length; index++) {
            const curElement = elements[index];
            if(curElement.classList.contains(_class)) {
                contains = true;
                break;
            }
        }
        return contains;
    }

Теперь вы можете использовать это так:

hasClass('body', 'gray')
hasClass('#like', 'green')
hasClass('.button', 'active')

Надеюсь, это поможет.

Для меня самый элегантный и быстрый способ добиться этого:

function hasClass(el,cl){
   return !!el.className && !!el.className.match(new RegExp('\\b('+cl+')\\b'));
}

Поскольку .className это строка, вы можете использовать строку includes() способ проверить, есть ли у вас .className включает имя вашего класса:

element.className.includes("class1")
Другие вопросы по тегам