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

588

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

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

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 = "";
}
<div id="test" class="class1"></div>

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

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

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

daGUY
источник
5
element.classList.contains (cls)
Ронни Ройстон

Ответы:

1039

Используйте метод: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;
    }
}

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

Феликс Клинг
источник
Удивительно, но как мне использовать это в сочетании с оператором switch, чтобы я мог изменить вывод в зависимости от того, какие классы содержит div?
daGUY
@daGUY: Что ты хочешь делать с оператором switch? Например, у второго divесть два класса, но он будет выводиться только I have class1при использовании break. Если вы хотите вывести каждый класс, который имеет элемент, то вы можете просто взять classNameи разделить его на пробелы. Или какова ваша настоящая цель?
Феликс Клинг
@Felix Kling: мне нужен innerHTML div, чтобы переключаться между четырьмя различными строками в зависимости от того, какой класс он содержит. Я просто использовал «У меня есть class1» и т. Д. В качестве примеров - реальные строки все разные. Я буду показывать только одну строку за раз, не объединяя ни одной (отсюда и разрывы после каждого случая). Я просто хочу, чтобы он все еще работал, даже если соответствующий класс является одним из нескольких классов в div.
daGUY
@ Феликс Клинг: это сделал, спасибо большое! На самом деле я не выводю имена классов, а скорее одну из четырех совершенно разных строк, поэтому я немного изменил ее с помощью нескольких операторов IF / ELSE IF для обработки каждого из них. Хотя работает отлично.
daGUY
1
Есть ли конкретная причина, по которой вы добавили пробелы до и после?
Ced
93

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

test.classList.contains(testClass);
разработчик
источник
3
containsметод в element.classListнедвижимости
user907860
7
NB! Поддерживается не во всех браузерах. Дополнительная информация здесь: caniuse.com/#feat=classlist
Silver Ringvee,
4
Это отличный ответ, и я считаю, что .contains () теперь имеет гораздо более широкую поддержку.
Николас Крайдберг
49

В современных браузерах вы можете просто использовать 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 .

Джон Слегерс
источник
10

Поскольку он хочет использовать 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/>";
    }
}
Думал
источник
1
Мне просто интересно то же самое, но да, это ближе всего к первоначальной проблеме!
Сильвер Рингви
8

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>

Просмотр совместимости браузера

Грант Миллер
источник
7

Вот небольшой фрагмент кода. Если вы пытаетесь проверить, содержит ли элемент класс, без использования 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);
};

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

document.getElementById('MyDiv').hasClass('active');
Кевал Бхатт
источник
Я предпочитаю это решение больше. Это позволяет избежать проблемы с именем класса, частично совпадающим с другим классом, и не требует, чтобы полифилы работали в IE.
scoota269
5

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

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

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

KooiInc
источник
1
Проблема с границами слова состоит в том, что некоторые допустимые символы для имен классов, такие как -, рассматриваются как границы слова. Например, ищет fooи класс foo-barдает true.
Феликс Клинг
Вы правы. Убрал оригинал, добавил другой подход. Все еще вкладчик.
KooiInc
5

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

// 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;
    }
}
Dementic
источник
use: 'element.hasClass (' classname ');
Дементик
Почему вы использовали t.length >>> 0? Насколько я знаю, если вы используете '0', то это неестественно, верно?
Витор Канова
вау так много кода для чего-то простого. Почему бы не использовать регулярные выражения и не изобретать велосипед? Вы можете просто использовать /^class_name_you_are_searching_for$/.test(myElement.className)
pqsk
1
Я написал это слишком быстро. Просто, чтобы не усложнять мое регулярное выражение, это было бы /\s*class_name_you_are_searching_for\s*/.test(myElement.className)
pqsk
@pqsk - я пишу свои собственные библиотеки для будущего использования. и это только добавляет в мой стек. Конечно, другие решения будут работать, это мой предпочтительный путь
Dementic
4

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

Дэвид
источник
1
Как насчет тестирования для класса classв приведенном выше примере?
Феликс Клинг
6
По опыту, этот метод может быть довольно рискованным: он вернет true, когда вы будете искать класс fooв элементе, который имеет foobarкласс.
Зирак
2
Конечно, вы просто должны знать, что вы тестируете. Код Феликса хорошо работает, используя пробелы в качестве разделителя.
Дэвид
Не в состоянии учитывать вложенные экземпляры имени класса. Пример: 'end' можно найти в имени класса 'frontend'.
Энтони Ратледж
4

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

if( document.body.className.match('category-page') ) { 
  console.log('yes');
}
TheBlackBenzKid
источник
1
этот метод может возвращать ложные срабатывания при поиске имени класса, которое частично соответствует - например, <body class="category-page">и document.body.className.match('page')- будет совпадать, но pageк элементу не прикреплен класс
hooblei
Может быть решен \b, например /\bpage\b/g, так как это регулярное выражение (примечание: нужно использовать / /g).
Андрей
2

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

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;
}
Андерс Фьелдстад
источник
2

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

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

}
Брэндон Брюл
источник
2

Я создал метод-прототип, который использует 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>

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

VSync
источник
Есть ли причина, по которой вы хотите использовать список классов вместо индекса e.className? Кажется, что перфоманс менее хорош
Ced
@Ced - хорошо, perf не имеет значения, если вы не тестируете тысячи элементов для их класса (вероятно, это будет изменено в браузерах в будущем). его более элегантно использовать, потому что код описывает его функциональность, но суть в том, что не важно, делай что хочешь :)
vsync
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; в вашем примере во всех случаях выполнялась аналогичная операция, но завтра вам может потребоваться выполнить разные действия для каждого из них.
    • Вы можете смоделировать случай по умолчанию, имея переменную состояния, сообщающую, найдено ли совпадение в цикле или нет.
entonio
источник
1

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

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

Эрик Янг
источник
1

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

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

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

Артур Тарасов
источник
1

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

hasClass (Vanilla JS)

function hasClass(element, cls) {
    return (' ' + element.className + ' ').indexOf(' ' + cls + ' ') > -1;
}
Jefsama
источник
1

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

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

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

В качестве альтернативы, если вы компилируете с babel, вы можете просто использовать: el.classList.contains(className);

Буц
источник
0

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

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;
};
Jimy
источник
1
Будьте осторожны с границей слова. Это также будет соответствовать истине, если у вас есть, например, класс foo-barи поиск foo.
Феликс Клинг
1
Привет, Джимми, поэтому я искал этот метасимвол \ b, и он рассматривает только [ a-zA-Z0-9_] как символы слова. Так что для имен классов, содержащих символ минус, это не сработает .
Стано
0

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

if ($(this).hasClass("your_Class")) 
    alert("positive");            
else              
    alert("Negative");
Абхишек
источник
8
1. «Использование простого JavaScript (не jQuery)» 2. Использование скобок
nkmol
3 - используйте круглые скобки
TheBlackBenzKid
0

в каком элементе в настоящее время находится класс .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 demo

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

Thielicious
источник
0

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

Измените hasCLass()функцию на:

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

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

Бен Рудольф
источник
0

Я создал эти функции для своего сайта, я использую только vanilla 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')

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

мистифицировать
источник
0

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

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

if(document.firstElementChild.classList.contains("your-class")){
    // <html> has 'your-class'
} else {
    // <html> doesn't have 'your-class'
}
Алиреза
источник
-1

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

function hasClass(el,cl){
   return !!el.className && !!el.className.match(new RegExp('\\b('+cl+')\\b'));
}
Pinonirvana
источник