¿Comprobar si un elemento contiene una clase en JavaScript?

588

Usando JavaScript simple (no jQuery), ¿hay alguna forma de verificar si un elemento contiene una clase?

Actualmente, estoy haciendo esto:

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>

El problema es que si cambio el HTML a esto ...

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

... ya no hay una coincidencia exacta, por lo que obtengo el resultado predeterminado de nothing ( ""). Pero todavía quiero que la salida sea I have class1porque <div>todavía contiene la .class1clase.

daGUY
fuente
55
element.classList.contains (cls)
Ronnie Royston el

Respuestas:

1039

Método de uso :element.classList .contains

element.classList.contains(class);

Esto funciona en todos los navegadores actuales y también hay polyfills para admitir navegadores más antiguos.


Alternativamente , si trabaja con navegadores antiguos y no desea usar polyfills para solucionarlos, el uso indexOfes correcto, pero debe modificarlo un poco:

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

De lo contrario, también obtendrá truesi la clase que está buscando es parte de otro nombre de clase.

MANIFESTACIÓN

jQuery usa un método similar (si no el mismo).


Aplicado al ejemplo:

Como esto no funciona junto con la instrucción switch, podría lograr el mismo efecto con 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;
    }
}

También es menos redundante;)

Felix Kling
fuente
Impresionante, pero ¿cómo lo uso en combinación con la instrucción switch para poder cambiar la salida según las clases que contiene el div?
daGUY
@daGUY: ¿Qué quieres hacer con la declaración de cambio de todos modos? Por ejemplo, el segundo divtiene dos clases, pero solo se generará I have class1como lo está utilizando break. Si desea generar todas las clases que tiene un elemento, puede tomarlo classNamey dividirlo en espacios en blanco. ¿O cuál es tu objetivo real?
Felix Kling,
@Felix Kling: necesito el innerHTML del div para cambiar entre cuatro cadenas diferentes según la clase que contenga. Acabo de usar "Tengo clase1", etc. como ejemplos: las cadenas reales son todas diferentes. Solo mostraré una cadena a la vez, sin combinar ninguna (de ahí los descansos después de cada caso). Solo quiero que siga funcionando incluso si la clase coincidente es una de varias clases en el div.
daGUY
@Felix Kling: eso lo hizo, ¡muchas gracias! En realidad, no estoy generando los nombres de las clases, sino una de cuatro cadenas completamente diferentes, por lo que lo modifiqué ligeramente con algunas declaraciones IF / ELSE IF para manejar cada una. Funciona perfectamente sin embargo.
daGUY
1
¿Hay alguna razón específica por la que agregaste espacios antes y después?
Ced
93

La solución fácil y efectiva es probar el método .contains .

test.classList.contains(testClass);
desarrollador
fuente
3
El containsmétodo de una element.classListpropiedad
user907860
77
¡NÓTESE BIEN! No es compatible con todos los navegadores, más información aquí: caniuse.com/#feat=classlist
Silver Ringvee
44
Esta es una gran respuesta y creo que .contains () tiene un soporte mucho más amplio ahora.
Nicholas Kreidberg
49

En los navegadores modernos, puede usar el containsmétodo de Element.classList:

testElement.classList.contains(className)

Manifestación

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 compatibles

ingrese la descripción de la imagen aquí

(de CanIUse.com )


Polyfill

Si desea usar Element.classListpero también desea admitir navegadores antiguos, considere usar este polyfill de Eli Gray .

John Slegers
fuente
10

Como quiere usar switch (), me sorprende que nadie haya presentado esto todavía:

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/>";
    }
}
Pensamiento
fuente
1
Me preguntaba lo mismo, pero sí, ¡eso es lo más cercano al problema original!
Silver Ringvee
8

Element.matches ()

element.matches (selectorString)

De acuerdo con MDN Web Docs :

El Element.matches()método devuelve truesi el elemento sería seleccionado por la cadena de selección especificada; de lo contrario, vuelve false.

Por lo tanto, puede usar Element.matches()para determinar si un elemento contiene una clase.

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

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

Ver compatibilidad del navegador

Grant Miller
fuente
7

Aquí hay un pequeño fragmento Si está intentando verificar si el elemento contiene una clase, sin usar jQuery.

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

Esto explica el hecho de que el elemento puede contener múltiples nombres de clase separados por espacio.

O


También puede asignar esta función al prototipo de elemento.

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

Y actívelo de esta manera (muy similar a la .hasClass()función de jQuery ):

document.getElementById('MyDiv').hasClass('active');
Keval Bhatt
fuente
Prefiero esta solución más. Evita el problema de que el nombre de la clase coincida parcialmente con otra clase y no requiere polyfills para funcionar en IE.
scoota269
5

Un oneliner simplificado: 1

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

1 indexOf para matrices no es compatible con IE (por supuesto). Hay muchos parches de monos en la red para eso.

KooiInc
fuente
1
El problema con los límites de las palabras es que algunos caracteres válidos para los nombres de clase, como los que -se consideran límites de las palabras. Por ejemplo, buscar fooy la clase es foo-barrendimientos true.
Felix Kling
Tienes razón. Se eliminó el original y se agregó otro enfoque. Sigue siendo una línea.
KooiInc 05 de
5

Esto es un poco viejo, pero tal vez alguien encuentre útil mi solución:

// 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;
    }
}
Demencial
fuente
use: 'element.hasClass (' nombre de clase ');
Demencial
¿Por qué usaste t.length >>> 0? Por lo que sé, es un noop si usas '0', ¿verdad?
Vitor Canova
wow tanto código para algo simple. ¿Por qué no usar una expresión regular y no reinventar la rueda? puedes usar /^class_name_you_are_searching_for$/.test(myElement.className)
pqsk
1
Escribí eso demasiado rápido. Solo para no complicar demasiado mi expresión regular sería /\s*class_name_you_are_searching_for\s*/.test(myElement.className)
pqsk
@pqsk: escribo mis propias bibliotecas para uso futuro. y esto solo se agrega a mi pila. por supuesto que otras soluciones funcionarían, esta es solo mi forma preferida
Dementic
4

classNamees solo una cadena para que pueda usar la función indexOf regular para ver si la lista de clases contiene otra cadena.

David
fuente
1
¿Qué pasa con las pruebas de clase classen el ejemplo anterior?
Felix Kling
66
Por experiencia, este método puede ser bastante arriesgado: volverá verdadero cuando busque la clase fooen un elemento que tiene la foobarclase.
Zirak
2
Claro, solo debes estar al tanto de lo que estás probando. El código de Felix funciona bien usando espacios como delimitador.
David
No tiene en cuenta las instancias anidadas de un nombre de clase. Ejemplo: 'fin' se puede encontrar en el nombre de la clase 'frontend'.
Anthony Rutledge
4

Sé que hay muchas respuestas, pero la mayoría de ellas son para funciones adicionales y clases adicionales. Este es el que yo personalmente uso; ¡Mucho más limpio y mucho menos líneas de código!

if( document.body.className.match('category-page') ) { 
  console.log('yes');
}
TheBlackBenzKid
fuente
1
este método puede devolver falsos positivos al buscar un nombre de clase que coincida parcialmente, por ejemplo, <body class="category-page">y document.body.className.match('page')coincidirá, pero no hay una clase pageasociada al elemento
hooblei
Se puede resolver con \b, por ejemplo /\bpage\b/g, ya que es regex (nota: tiene que usar / /g).
Andrew
2

Aquí hay una solución trivial insensible a mayúsculas y 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
fuente
2

Si el elemento solo tiene un nombre de clase, puede verificarlo rápidamente obteniendo el atributo de clase. Las otras respuestas son mucho más robustas, pero esto ciertamente tiene sus casos de uso.

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

}
Brandon Brule
fuente
2

He creado un método prototipo que utiliza classList, si es posible, de lo contrario recurre a 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 prueba

vsync
fuente
¿Hay alguna razón por la que quieras usar classlist en lugar del índice de e.className? Parece que el rendimiento es menos bueno
Ced
@Ced: bueno, el rendimiento es irrelevante si no está probando miles de elementos para su clase (probablemente se refactorizará en los navegadores en el futuro). es más elegante de usar porque el código describe su funcionalidad, pero en
resumen
1
  1. El truco de Felix de agregar espacios para flanquear el className y la cadena que está buscando es el enfoque correcto para determinar si los elementos tienen la clase o no.

  2. Para tener un comportamiento diferente según la clase, puede usar referencias de funciones, o funciones, dentro de un 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);
        }
    }
    • for (var i in fns) itera a través de las teclas dentro del mapa fns.
    • No tener interrupción después de fnsi permite que el código se ejecute siempre que haya una coincidencia, de modo que si el elemento tiene, fi, class1 y class2, se ejecutarán fn1 y fn2.
    • La ventaja de este enfoque es que el código a ejecutar para cada clase es arbitrario, como el de la instrucción switch; en su ejemplo, todos los casos realizaron una operación similar, pero mañana puede que tenga que hacer cosas diferentes para cada uno.
    • Puede simular el caso predeterminado haciendo que una variable de estado indique si se encontró una coincidencia en el bucle o no.
entonio
fuente
1

Poly llenaría la funcionalidad classList y usaría la nueva sintaxis. De esta forma, los navegadores más nuevos utilizarán la nueva implementación (que es mucho más rápida) y solo los navegadores antiguos recibirán el impacto del rendimiento del código.

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

Eric Young
fuente
1

Esto está un poco apagado, pero si tiene un evento que desencadena el cambio, puede prescindir de las clases:

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

Tu puedes hacer

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

Es un poco hacky, pero funciona para interruptores largos sin funciones o bucles adicionales

Arthur Tarasov
fuente
1

¡Vea este enlace de Codepen para una forma más rápida y fácil de verificar un elemento si tiene una clase específica usando JavaScript vainilla ~!

hasClass (Vanilla JS)

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

Esto es compatible con IE8 +.

Primero verificamos si classListexiste, si es así, podemos usar el containsmétodo que es compatible con IE10 +. Si estamos en IE9 u 8, recurrir al uso de una expresión regular, que no es tan eficiente pero es un polyfill conciso.

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

Alternativamente, si está compilando con babel, simplemente puede usar: el.classList.contains(className);

Peros
fuente
0

Prueba 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
fuente
1
Tenga cuidado con la palabra límite. También coincidirá con true si tiene, por ejemplo, una clase foo-bary busca foo.
Felix Kling
1
Hola Jimy, estaba buscando este metacarácter \ b y solo considera [ a-zA-Z0-9_] como caracteres de palabras. Entonces, para los nombres de clase que contienen un carácter negativo, esto no funcionará .
Stano
0

Creo que la solución perfecta será esta

if ($(this).hasClass("your_Class")) 
    alert("positive");            
else              
    alert("Negative");
Abhishek
fuente
8
1. "Uso de JavaScript simple (no jQuery)" 2. Use paréntesis
nkmol
3 - uso Paréntesis
TheBlackBenzKid
0

¿en qué elemento está actualmente la clase '.bar'? Aquí hay otra solución, pero depende de usted.

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

Por supuesto, esto es solo una búsqueda de 1 elemento simple <img>( /Image/g), pero puede poner todo en una matriz como <li>is /LI/g, <ul>= /UL/getc.

Thielicious
fuente
0

Solo para agregar a la respuesta a las personas que intentan encontrar nombres de clase dentro de elementos SVG en línea.

Cambia la hasCLass()función a:

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

En lugar de utilizar la classNamepropiedad, deberá utilizar el getAttribute()método para obtener el nombre de la clase.

Ben Rudolph
fuente
0

Creé estas funciones para mi sitio web, solo uso JavaScript de vainilla, tal vez ayude a alguien. Primero creé una función para obtener cualquier 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;
    }

Luego la función que recibe la clase a eliminar y el selector del 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;
    }

Ahora puedes usarlo así:

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

Espero que ayude.

Josh
fuente
0

Consejo: Intente eliminar las dependencias de jQuery en sus proyectos tanto como pueda: VanillaJS .

document.firstElementChilddevuelve la <html>etiqueta y el classListatributo devuelve todas las clases agregadas a él.

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

Para mí, la forma más elegante y rápida de lograrlo es:

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