En javascript directo (es decir, sin extensiones como jQuery, etc.), ¿hay alguna manera de determinar el índice de un nodo secundario dentro de su nodo principal sin iterar y comparar todos los nodos secundarios?
P.ej,
var child = document.getElementById('my_element');
var parent = child.parentNode;
var childNodes = parent.childNodes;
var count = childNodes.length;
var child_index;
for (var i = 0; i < count; ++i) {
if (child === childNodes[i]) {
child_index = i;
break;
}
}
¿Existe una mejor manera de determinar el índice del niño?
javascript
dom
Todos los trabajadores son esenciales
fuente
fuente
parent.childNodes
, en lugar deparent.children
?. Este último solo enumera losElements
, excluyendo en particular losText
nodos ... Algunas de las respuestas aquí, por ejemplo, el usopreviousSibling
, se basan en el uso de todos los nodos secundarios, mientras que otras solo se preocupan por los niños que sonElement
s ... (!).childNodes
definitivamente debería usarse en lugar de.children
. Las 2 respuestas principales publicadas darán resultados diferentes, como señaló.Respuestas:
puede usar la
previousSibling
propiedad para iterar a través de los hermanos hasta que regresenull
y cuente cuántos hermanos ha encontrado:Tenga en cuenta que en lenguajes como Java, hay una
getPreviousSibling()
función, sin embargo en JS esto se ha convertido en una propiedad -previousSibling
.fuente
for (var i=0; (node=node.previousSibling); i++);
i
lo que será accesible..previousSibling
y.previousElementSibling
. El primero llega a los nodos de texto, el segundo no.Me ha gustado usar
indexOf
para esto. Debido a queindexOf
está encendidoArray.prototype
yparent.children
es aNodeList
, tienes que usarcall();
Es un poco feo, pero es una línea y usa funciones con las que cualquier desarrollador de javascript debería estar familiarizado de todos modos.fuente
[]
crea una instancia de Array cada vez que ejecuta ese código, que es menos eficiente para la memoria y GC que el usoArray.prototype
.[]
se limpia la memoria como valor basura?[].indexOf
el motor hay que crear una instancia de matriz solo para acceder a laindexOf
implementación en el prototipo. La instancia en sí no se usa (hace GC, no es una fuga, solo está desperdiciando ciclos).Array.prototype.indexOf
accede a esa implementación directamente sin asignar una instancia anónima. La diferencia será insignificante en casi todas las circunstancias, por lo que, francamente, puede que no valga la pena preocuparse por ella.ES6:
Explicación:
element.parentNode.children
→ Devuelve los hermanos deelement
, incluido ese elemento.Array.from
→ Lanza el constructor dechildren
a unArray
objetoindexOf
→ Puede postularseindexOf
porque ahora tiene unArray
objeto.fuente
Array.from
trabajos en Internet Explorercreates a new Array instance from an array-like or iterable object.
Crear una nueva instancia de matriz solo para encontrar un índice podría no ser eficiente en memoria o GC, dependiendo de la frecuencia de la operación, en cuyo caso la iteración, como se explica en la respuesta aceptada, sería más ideal.ES: más corto
El operador de propagación es un atajo para eso
fuente
e.parentElement.childNodes
ye.parentNode.children
?childNodes
también incluye nodos de textoType 'NodeListOf<ChildNode>' must have a '[Symbol.iterator]()' method that returns an iterator.ts(2488)
Añadiendo un elemento (prefijado por seguridad) .getParentIndex ():
fuente
if (!Element.prototype.getParentIndex) Element.prototype.getParentIndex = function(){ /* code here */ }
? De todos modos, si esto se implementa alguna vez en el estándar en el futuro, es probable que se implemente como un getterelement.parentIndex
. Entonces, diría que el mejor enfoque seríaif(!Element.prototype.getParentIndex) Element.prototype.getParentIndex=Element.prototype.parentIndex?function() {return this.parentIndex}:function() {return Array.prototype.indexOf.call(this.parentNode.children, this)}
getParentIndex()
puede tener una firma diferente a su implementación.Supongo que dado un elemento en el que todos sus elementos secundarios están ordenados en el documento secuencialmente, la forma más rápida debería ser hacer una búsqueda binaria, comparando las posiciones del documento de los elementos. Sin embargo, como se introdujo en la conclusión, se rechaza la hipótesis. Cuantos más elementos tenga, mayor será el potencial de rendimiento. Por ejemplo, si tuviera 256 elementos, entonces (de manera óptima) ¡solo necesitaría verificar solo 16 de ellos! ¡Para 65536, solo 256! ¡El rendimiento crece a la potencia de 2! Ver más números / estadísticas. Visite Wikipedia
Entonces, la forma en que lo usa es obteniendo la propiedad 'parentIndex' de cualquier elemento. Por ejemplo, consulte la siguiente demostración.
Limitaciones
Binary VS Linear Search en 200 mil elementos (puede fallar algunos navegadores móviles, ¡CUIDADO!):
Búsqueda binaria
Mostrar fragmento de código
Búsqueda lineal hacia atrás (`lastIndexOf`)
Mostrar fragmento de código
Búsqueda lineal hacia adelante (`indexOf`)
Mostrar fragmento de código
AnteriorElementSibling Counter Search
Cuenta el número de PreviousElementSiblings para obtener parentIndex.
Mostrar fragmento de código
Sin búsqueda
Para comparar cuál sería el resultado de la prueba si el navegador optimizara la búsqueda.
Mostrar fragmento de código
La Conculsion
Sin embargo, después de ver los resultados en Chrome, los resultados son opuestos a lo esperado. La búsqueda lineal hacia adelante más tonta fue un sorprendente 187 ms, 3850%, más rápida que la búsqueda binaria. Evidentemente, Chrome de alguna manera superó mágicamente al
console.assert
y lo optimizó, o (de manera más optimista) Chrome utiliza internamente un sistema de indexación numérica para el DOM, y este sistema de indexación interno se expone a través de las optimizaciones aplicadasArray.prototype.indexOf
cuando se usa en unHTMLCollection
objeto.fuente
Utilice el algoritmo de búsqueda binaria para mejorar el rendimiento cuando el nodo tiene muchos hermanos.
fuente
Tuve un problema con los nodos de texto y mostraba un índice incorrecto. Aquí hay una versión para solucionarlo.
fuente
Ex
fuente
Element.prototype
? Las funciones parecen útiles, pero no sé qué hacen estas funciones (incluso si los nombres son obvios).el.group.value()
??. Mi primer comentario está ahí para mejorar la calidad de su respuesta.¿Podrías hacer algo como esto?
https://developer.mozilla.org/en-US/docs/Web/API/Node/parentElement
fuente
fuente