Contenido

getElementsByClassName versión 2008

4 Jul

+ 9

Robert Nyman publicó en 2005 un artículo en el que mostraba la «Ultimate getElementsByClassName«, una función desarrollada en Javascript que sin necesidad de usar ningún tipo de framework nos permite obtener todos los elementos de una misma clase pasada por parámetro.

Ultimate getElementsByClassName (2005)

function getElementsByClassName(oElm, strTagName, strClassName){
    var arrElements = (strTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(strTagName);
    var arrReturnElements = new Array();
    strClassName = strClassName.replace(/\-/g, "\\-");
    var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$)");
    var oElement;
    for(var i=0; i<arrElements.length; i++){
        oElement = arrElements[i];
        if(oRegExp.test(oElement.className)){
            arrReturnElements.push(oElement);
        }
    }
    return (arrReturnElements)
}

Esta funcionalidad que actualmente está contemplada para el estandar y que será integrada en todos los navegadores futuros, nos ahorrará muchas líneas de código cuando esté implementada como parte del núcleo del navegador.
Robert ha desarrollado de nuevo la función, añadiéndole una serie de mejoras que han hecho crecer considerablemente la función:

Ultimate getElementsByClassName (2008)

/*
	Developed by Robert Nyman, http://www.robertnyman.com
	Code/licensing: http://code.google.com/p/getelementsbyclassname/
*/
var getElementsByClassName = function (className, tag, elm){
	if (document.getElementsByClassName) {
		getElementsByClassName = function (className, tag, elm) {
			elm = elm || document;
			var elements = elm.getElementsByClassName(className),
				nodeName = (tag)? new RegExp("\\b" + tag + "\\b", "i") : null,
				returnElements = [],
				current;
			for(var i=0, il=elements.length; i<il; i+=1){
				current = elements[i];
				if(!nodeName || nodeName.test(current.nodeName)) {
					returnElements.push(current);
				}
			}
			return returnElements;
		};
	}
	else if (document.evaluate) {
		getElementsByClassName = function (className, tag, elm) {
			tag = tag || "*";
			elm = elm || document;
			var classes = className.split(" "),
				classesToCheck = "",
				xhtmlNamespace = "http://www.w3.org/1999/xhtml",
				namespaceResolver = (document.documentElement.namespaceURI === xhtmlNamespace)? xhtmlNamespace : null,
				returnElements = [],
				elements,
				node;
			for(var j=0, jl=classes.length; j<jl; j+=1){
				classesToCheck += "[contains(concat(' ', @class, ' '), ' " + classes[j] + " ')]";
			}
			try	{
				elements = document.evaluate(".//" + tag + classesToCheck, elm, namespaceResolver, 0, null);
			}
			catch (e) {
				elements = document.evaluate(".//" + tag + classesToCheck, elm, null, 0, null);
			}
			while ((node = elements.iterateNext())) {
				returnElements.push(node);
			}
			return returnElements;
		};
	}
	else {
		getElementsByClassName = function (className, tag, elm) {
			tag = tag || "*";
			elm = elm || document;
			var classes = className.split(" "),
				classesToCheck = [],
				elements = (tag === "*" && elm.all)? elm.all : elm.getElementsByTagName(tag),
				current,
				returnElements = [],
				match;
			for(var k=0, kl=classes.length; k<kl; k+=1){
				classesToCheck.push(new RegExp("(^|\\s)" + classes[k] + "(\\s|$)"));
			}
			for(var l=0, ll=elements.length; l<ll; l+=1){
				current = elements[l];
				match = false;
				for(var m=0, ml=classesToCheck.length; m<ml; m+=1){
					match = classesToCheck[m].test(current.className);
					if (!match) {
						break;
					}
				}
				if (match) {
					returnElements.push(current);
				}
			}
			return returnElements;
		};
	}
	return getElementsByClassName(className, tag, elm);
};

Nuevas funcionalidades

  • Utiliza getElementsByClassName nativo si está disponible
  • Utiliza XPath nativo si está disponible
  • Soporta múltiples class en una misma petición
  • Devuelve un array con el que trabajar.

Modo de uso

La función puede recibir 3 parámetros:

  • class: El class que estamos buscando. Obligatorio.
  • tag: El tag que contiene la class. Opcional.
  • elm: Elemento padre desde el que empezar a buscar.Opcional
getElementsByClassName(class, tag, elm);
// Ejemplos
getElementsByClassName("rojo"); // Todos los elementos con class="rojo"
getElementsByClassName("rojo azul grande"); //Todos los elements con class="rojo", class="azul",...
getElementsByClassName("rojo", "p"); //Todas las P con class="rojo"
getElementsByClassName("rojo", "p", document.getElementById("content")); // Todas las P con class="rojo" en el elemento content e hijos.

Para realizar una búsqueda por más de una class, deberemos separarlas por espacios en el parámetro class.

  • Para cualquier página mínimamente seria que requiere hacer uso de javascript y tengas/quieras seleccionar elementos por su clase, ¿por qué narices no usar una librería? jquery/prototype/mootols/*, solventarás muchísimos incompatibilidades y te facilitarás la vida.

    Para hacernos pajas mentales siempre hay oportunidades.

  • @Blaxter: Hombre, si solo necesitas conocer los elementos de una clase específica ¿por que vamos a meter un framework con soporte Ajax, json, drag&drop, efectos,… si no lo vamos a usar?

    Los frameworks nos están haciendo que nos olvidemos de como se desarrolla en Javascript. No debemos olvidar las raíces, siempre es bueno conocer de donde vienen cosas como $$() o $().

  • Mucho más completa, excelentes noticias cuando no queremos usar un Framework como bien marcaste.

  • @Blaxter: Están los que utilizan frameworks como vos y están los que son capaces de hacerse sus propios frameworks o incluso hacer los que vos utilizas. A éstos últimos les interesan este tipo de artículos.

    Siempre utilice en estos casos getElementsByTagName y luego dentro compruebo element.className.
    Esta función está muy bien pensada.

    Saludos!

  • como bien dice anieto depende de las necesidades del momento, si uno esta usando un framework que ya dispone de esta clase entonces no nos preocupamos, pero a la hora de necesitar seleccionar un elemento por su clase para que vamos a instalar una framework por mas disminuido en su contenido que este.
    Use mucho la clase getElementsByClassName para algunos proyectos en mi trabajo y ahora con estos nuevos cambios veo que habria obviado muchas lineas de codigo.
    Saludos y como siempre muy buen material.

  • Muy interesante la optimización hasta donde se pueda. Lo malo de usar un framework es que para cosas pequeñas cargas unha liberia tocha, de hecho me estoi planteando hacer una mini-libreria que solo sirba para hacer consultas dom y algo de ajax moi basico.

Comentar

#

Me reservo el derecho de eliminar y/o modificar los comentarios que contengan lenguaje inapropiado, spam u otras conductas no apropiadas en una comunidad civilizada. Si tu comentario no aparece, puede ser que akismet lo haya capturado, cada día lo reviso y lo coloco en su lugar. Siento las molestias.