Verificar se um elemento contém uma classe em JavaScript?

588

Usando JavaScript simples (não jQuery), existe alguma maneira de verificar se um elemento contém uma classe?

Atualmente, estou fazendo o seguinte:

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>

A questão é que, se eu mudar o HTML para este ...

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

... não há mais uma correspondência exata, então recebo a saída padrão de nothing ( ""). Mas ainda quero que a saída seja I have class1porque <div>ainda contém a .class1classe.

daGUY
fonte
5
element.classList.contains (CLS)
Ronnie Royston

Respostas:

1039

Use o método:element.classList .contains

element.classList.contains(class);

Isso funciona em todos os navegadores atuais e também há polyfills para oferecer suporte a navegadores mais antigos.


Como alternativa , se você trabalha com navegadores mais antigos e não deseja usar os polyfills para corrigi-los, o uso indexOfé correto, mas é necessário ajustá-lo um pouco:

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

Caso contrário, você também obterá truese a classe que você está procurando faz parte de outro nome de classe.

DEMO

O jQuery usa um método semelhante (se não o mesmo).


Aplicado ao exemplo:

Como isso não funciona junto com a instrução switch, você pode obter o mesmo efeito com este código:

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;
    }
}

Também é menos redundante;)

Felix Kling
fonte
Impressionante, mas como eu uso isso em combinação com a instrução switch para que eu possa alterar a saída com base em quais classes a div contém?
DaGUY 5/05
@daGUY: O que você quer fazer com a instrução switch? Por exemplo, o segundo divpossui duas classes, mas somente produzirá I have class1como você está usando break. Se você deseja gerar todas as classes que um elemento possui, basta pegar classNamee dividir em espaços em branco. Ou qual é o seu objetivo real?
Felix Kling
@ Felix Kling: Eu preciso do innerHTML da div para mudar entre quatro strings diferentes, dependendo da classe que ela contém. Eu apenas usei "tenho classe1" etc. como exemplos - as strings reais são todas diferentes. Eu mostrarei apenas uma string de cada vez, sem combinar nenhuma (daí as quebras após cada caso). Eu só quero que ele ainda funcione, mesmo que a classe correspondente seja uma das várias classes na div.
daGUY 5/05
@ Felix Kling: fez isso, muito obrigado! Na verdade, não estou exibindo os nomes das classes, mas uma das quatro seqüências totalmente diferentes, então a modifiquei levemente com algumas instruções IF / ELSE IF para lidar com cada uma. Funciona perfeitamente embora.
DaGUY 5/05
1
Existe uma razão específica pela qual você adicionou espaços antes e depois?
Ced
93

A solução fácil e eficaz é tentar o método .contains .

test.classList.contains(testClass);
desenvolvedor
fonte
3
o containsmétodo de uma element.classListpropriedade
user907860
7
NB! Não há suporte para todos os navegadores, mais informações aqui: caniuse.com/#feat=classlist
Silver Ringvee
4
Esta é uma ótima resposta e acredito que .contains () tem um suporte muito mais amplo agora.
Nicholas Kreidberg
49

Nos navegadores modernos, você pode simplesmente usar o containsmétodo de Element.classList:

testElement.classList.contains(className)

Demo

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>


Navegadores suportados

insira a descrição da imagem aqui

(de CanIUse.com )


Polyfill

Se você deseja usar, Element.classListmas também deseja oferecer suporte a navegadores antigos, considere usar esse polyfill da Eli Gray .

John Slegers
fonte
10

Como ele deseja usar o switch (), estou surpreso que ninguém tenha feito isso ainda:

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/>";
    }
}
Pensamento
fonte
1
Eu estava pensando a mesma coisa, mas sim, isso é o mais próximo do problema original!
Silver Ringvee 29/03/16
8

Element.matches ()

element.matches (selectorString)

De acordo com o MDN Web Docs :

O Element.matches()método retornará truese o elemento for selecionado pela sequência de seleção selecionada; caso contrário, retorna false.

Portanto, você pode usar Element.matches()para determinar se um elemento contém uma classe.

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

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

Exibir compatibilidade do navegador

Grant Miller
fonte
7

Aqui está um pequeno trecho Se você está tentando verificar se o elemento contém uma classe, sem usar o jQuery.

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

Isso explica o fato de que o elemento pode conter vários nomes de classe separados por espaço.

OU


Você também pode atribuir esta função ao protótipo do elemento.

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

E ative-o assim (muito semelhante à .hasClass()função do jQuery ):

document.getElementById('MyDiv').hasClass('active');
Keval Bhatt
fonte
Eu prefiro mais esta solução. Evita que o nome da classe corresponda parcialmente a outra classe e não exige que os polyfills funcionem no IE.
precisa saber é o seguinte
5

Um oneliner simplificado: 1

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

1 indexOf para matrizes não é suportado pelo IE (é claro). Existem muitas manchas de macacos na rede para isso.

KooiInc
fonte
1
O problema com os limites de palavras é que alguns caracteres válidos para nomes de classes, como -são considerados limites de palavras. Por exemplo, procurando fooe a classe é foo-barrendimentos true.
Felix Kling 5/05
Você está certo. Removido o original, adicionado outra abordagem. Ainda um oneliner.
KooiInc 5/05
5

Isso é um pouco antigo, mas talvez alguém ache minha solução útil:

// 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
fonte
use: 'element.hasClass (' classname ');
Dementic
Por que você usou t.length >>> 0? Tanto quanto eu sei, é um noop se você usar '0', certo?
Vitor Canova
wow tanto código para algo simples. Por que não usar uma expressão regular e não reinventar a roda? você pode simplesmente usar /^class_name_you_are_searching_for$/.test(myElement.className)
pqsk
1
Eu escrevi isso muito rápido. Só para não complicar a minha expressão regular seria /\s*class_name_you_are_searching_for\s*/.test(myElement.className)
pqsk
@pqsk - escrevo minhas próprias bibliotecas para uso futuro. e isso apenas aumenta a minha pilha. é claro que outras soluções iria funcionar, esta é apenas a minha maneira preferida
Dementic
4

classNameé apenas uma sequência, para que você possa usar a função indexOf regular para verificar se a lista de classes contém outra sequência.

David
fonte
1
E quanto ao teste para a classe classno exemplo acima?
Felix Kling 5/05
6
Por experiência, esse método pode ser bastante arriscado: ele retornará verdadeiro quando você procurar a classe fooem um elemento que a tenha foobar.
Zirak 5/05
2
Claro, você apenas está ciente do que está testando. O código de Felix funciona bem usando espaços como delimitador.
David
Não considera instâncias aninhadas de um nome de classe. Exemplo: 'end' pode ser encontrado no nome da classe 'frontend'.
Anthony Rutledge
4

Eu sei que existem muitas respostas, mas a maioria delas é para funções adicionais e classes adicionais. Esse é o que eu pessoalmente uso; muito mais limpo e muito menos linhas de código!

if( document.body.className.match('category-page') ) { 
  console.log('yes');
}
TheBlackBenzKid
fonte
1
este método pode retornar falsos positivos ao procurar por um nome de classe que corresponde parcialmente - por exemplo, <body class="category-page">e document.body.className.match('page')- irá corresponder, mas não há nenhuma classe pageanexado ao elemento
hooblei
Pode ser resolvido com \b, por exemplo /\bpage\b/g, uma vez que é regex (nota: precisa usar / /g).
Andrew
2

Aqui está uma solução trivial que não diferencia maiúsculas de minúsculas:

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;
}
Anders Fjeldstad
fonte
2

Se o elemento tiver apenas um nome de classe, você poderá verificar rapidamente obtendo o atributo de classe. As outras respostas são muito mais robustas, mas isso certamente tem seus casos de uso.

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

}
Brandon Brule
fonte
2

Eu criei um método de protótipo que usa classList, se possível, outro recurso para 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>

Página de teste

vsync
fonte
Existe uma razão para você querer usar a lista de classes em vez do índice de e.className? Parece que o perf são menos bons
Ced
@ Ced - bem, o perf é irrelevante se você não estiver testando milhares de elementos para sua classe (provavelmente será refatorado em navegadores no futuro). é mais elegante de usar, porque o código descreve sua funcionalidade, mas linha de fundo, não importa, não o que quiser :)
vsync
1
  1. O truque de Felix de adicionar espaços para flanquear o className e a string que você está procurando é a abordagem certa para determinar se os elementos têm a classe ou não.

  2. Para ter um comportamento diferente de acordo com a classe, você pode usar referências de função, ou funções, dentro de um mapa:

    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);
        }
    }
    • para (var i in fns) itera pelas chaves dentro do mapa fns.
    • Não ter interrupção após fnsi permite que o código seja executado sempre que houver uma correspondência - de modo que, se o elemento tiver, fi, classe1 e classe2, ambos fn1 e fn2 serão executados.
    • A vantagem dessa abordagem é que o código a ser executado para cada classe é arbitrário, como o código da instrução switch; no seu exemplo, todos os casos executaram uma operação semelhante, mas amanhã você pode precisar fazer coisas diferentes para cada um.
    • Você pode simular o caso padrão tendo uma variável de status informando se uma correspondência foi encontrada no loop ou não.
entonio
fonte
1

Gostaria Poly preencher a funcionalidade classList e usar a nova sintaxe. Dessa forma, um navegador mais novo usará a nova implementação (que é muito mais rápida) e apenas navegadores antigos receberão o desempenho atingido pelo código.

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

Eric Young
fonte
1

Isso está um pouco errado, mas se você tiver um evento que aciona a opção, poderá ficar sem as classes:

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

Você pode fazer

$('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, '')remove dígitos de id.

É um pouco hacky, mas funciona para switches longos sem funções extras ou loops

Arthur Tarasov
fonte
1

Veja este link do Codepen para uma maneira mais rápida e fácil de verificar um elemento se ele tiver uma classe específica usando JavaScript vanilla ~!

hasClass (Vanilla JS)

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

Isso é suportado no IE8 +.

Primeiro, verificamos se classListexiste. Podemos usar o containsmétodo suportado pelo IE10 +. Se estivermos no IE9 ou 8, ele voltará a usar um regex, que não é tão eficiente, mas é um polyfill conciso.

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

Como alternativa, se você estiver compilando com babel, pode simplesmente usar: el.classList.contains(className);

Buts
fonte
0

Tente este:

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
fonte
1
Tenha cuidado com o limite da palavra. Também corresponderá a verdadeiro se você tiver, por exemplo, uma classe foo-bare a procura foo.
Felix Kling 5/05
1
Oi Jimy, eu estava procurando por esse metacaractere \ b e ele considera apenas [ a-zA-Z0-9_] como caracteres de palavra. Portanto, para nomes de classe contendo um caractere de menos isso não funcionará .
Stano
0

Eu acho que a solução perfeita será essa

if ($(this).hasClass("your_Class")) 
    alert("positive");            
else              
    alert("Negative");
Abhishek
fonte
8
1. "Usando JavaScript simples (não jQuery)" 2. Use colchetes
nkmol
3 - use Parênteses
TheBlackBenzKid
0

em qual elemento está atualmente a classe '.bar'? Aqui está outra solução, mas depende de você.

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);
}

demonstração do jsfiddle

Claro que isso é apenas uma pesquisa para 1 elemento simples <img>( /Image/g), mas você pode colocar tudo em uma matriz como <li>is /LI/g, <ul>= /UL/getc.

Thielicious
fonte
0

Apenas para adicionar à resposta as pessoas que tentam encontrar nomes de classes nos elementos SVG embutidos.

Mude a hasCLass()função para:

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

Em vez de usar a classNamepropriedade, você precisará usar o getAttribute()método para pegar o nome da classe.

Ben Rudolph
fonte
0

Criei essas funções para o meu site, uso apenas javascript de baunilha, talvez isso ajude alguém. Primeiro, criei uma função para obter qualquer elemento 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;
    }

Em seguida, a função que recebe a classe a ser removida e o seletor do elemento:

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;
    }

Agora você pode usá-lo assim:

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

Espero que ajude.

Josh
fonte
0

Dica: Tente remover as dependências do jQuery em seus projetos o máximo que puder - VanillaJS .

document.firstElementChildretorna a <html>tag, o classListatributo retorna todas as classes adicionadas a ela.

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

Para mim, a maneira mais elegante e rápida de alcançá-lo é:

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