2010-03-12 16 views
17

Originalmente estaba pidiendo una forma elegante de simular la funcionalidad Array.concat() en los resultados de la función getElementsByTagName en IE o navegadores más antiguos, porque parecía que concat no era compatible. Solo que, por supuesto, lo es - la razón por la cual el objeto devuelto no lo soportó es porque no es un Array. Oops!Javascript - Concatenar múltiples NodeLists juntos

getElementsByTagName en realidad devuelve un NodeList. La verdadera pregunta, entonces, es: ¿cuál es una buena manera de obtener una lista única de todos los elementos del formulario en un documento (entrada, seleccionar, área de texto, botón) para recorrerlos? No se requiere una matriz ... un solo NodeList sería perfecto, también.

Tenga en cuenta que estoy usando IE6 ya que esto es para una intranet corporativa (aunque pronto IE8).

La respuesta que se me ocurrió fue:

  • Se hizo más simple y probablemente se comportó mejor que sólo hay que poner el código en una función separada y llamarla tres veces con las diferentes NodeLists, en lugar de preocuparse por una buena manera de agruparlos en uno.

  • Al final me cambié al uso de MooTools (después de varias horas leyendo las comparaciones de todos los diferentes marcos). Entonces, obtener una matriz de los elementos que quiero es muy simple. Recomiendo usar un marco de JavaScript como este en lugar de que la gente se desanime tratando de descubrir la mejor manera de hacer las cosas. Por supuesto que estoy totalmente interesado en aprender el lenguaje en bruto (razón por la cual he evitado usar un framework por tanto tiempo) pero no siempre es la manera más rápida de hacer que las cosas funcionen, lo que en un negocio a menudo importa tanto. como mejorar la habilidad del codificador con el lenguaje.

Actualización: ¡casi 2 años más tarde solo usaría jQuery y terminaré con eso!

+2

IE lo admite, ¿puede aclarar un poco la pregunta? –

+0

Usar jQuery es definitivamente el camino a seguir. Me encontré con esto en un caso donde no tenía acceso a jQuery, sin embargo. Terminé creando una matriz de etiquetas de elementos en las que quería actuar y recorriendo todo, llamando a getElementsByTagName para cada una. Me pregunto si eso es más o menos eficiente que la respuesta principal. – bpscott

+0

@bpscott ¿Pero pusiste todos los elementos en una sola matriz en cualquier punto, o simplemente trabajas con ellos una sola etiqueta a la vez? – ErikE

Respuesta

31

Para concatenar las listas de nodos, conviértalas en matrices usando Array.prototype.slice.call y luego concatúrelas normalmente.

var a = Array.prototype.slice.call(document.getElementsByTagName("p")), 
    b = Array.prototype.slice.call(document.getElementsByTagName("div")) 

var c = a.concat(b); 

Editar: (en respuesta a tu comentario)

Si sólo tiene unos pocos tipos de elementos, esto está bien, pero el rendimiento disminuye con el número de llamadas que realiza DOM. Puede ser mejor y más rápido hacer un document.getElementsByTagName('*'), recorrer la lista y elegir los elementos con el nodeName requerido.

Otra cosa a tener en cuenta es que el método Array.prototype.slice utilizado anteriormente puede no funcionar en TODOS los navegadores. Echa un vistazo a la línea de comentario # 723 en sizzle.js (el motor selector detrás de jQuery)

Por supuesto, es mejor usar una biblioteca como jQuery que maneje todos los dolores de cabeza.Simplemente puede hacer:

$("input, select, textarea, <other tags>") 
+0

Estaba buscando una manera simple de obtener una lista de elementos múltiples (en este caso, elementos de formulario INPUT, SELECT, TEXTAREA y posiblemente BUTTON). Es esta la mejor manera? Supongo que es hora de abrir una nueva pregunta. – ErikE

+0

@Emtucifor: He actualizado mi respuesta. –

+0

Se necesita una cita para la llamada a document.getElementsByTagName ("*"), y nodeName es lo que hay que buscar. –

1
var a1=document.getElementsByTagName('div'), 
a2=document.getElementsByTagName('button'); 
a1=[].slice.call(a1, 0,a1.length).concat([].slice.call(a2, 0,a2.length)) 
3
function mergeNodeLists(a, b) { 
    var slice = Array.prototype.slice; 
    return slice.call(a).concat(slice.call(b)); 
} 

console.log(mergeNodeLists(inputs, selects)); // => [input, select]

+1

. Realmente no veo que esto agregue mucho más a la respuesta seleccionada. ¡Gracias por participar! – ErikE

0

que había de pensamiento no habría habido más respuestas que esto, de todas formas he dado a este un tiro y se le ocurrió la siguiente función aunque tuve que golpear mi cabeza un poco.

function group_elements(element, tags) { 
    var elements = element.getElementsByTagName('*'); 
    var results = []; 
    for (var i = 0; i < elements.length; ++i) { 
     if (tags.indexOf(elements[i].nodeName.toLowerCase()) > -1) { 
     results.push(elements[i]); 
     } 
    } 
    return results; 
} 


var form = document.getElementById('form'); 
var tags = ['input', 'select']; 
console.log(group_elements(form, tags)); 
+0

Problemas: no use una cadena, use una matriz: 'var nodes = ['input', 'select'];' luego no es necesario dividir. No modifique los parámetros. La redefinición de parámetros no tiene sentido. 'node' no es un buen nombre, pruebe 'tagName' (son cadenas, no objetos de nodo). JavaScript idiomáticamente utiliza camelCase, por lo que 'selected_elements' debe ser' selectedElements'. – ErikE

0

Como se señaló en el MDN Documentation, también se puede utilizar para convertir un Array.from NodeList a una matriz en los navegadores que lo soportan.