Em javascript direto (ou seja, sem extensões como jQuery, etc.), há uma maneira de determinar o índice de um nó filho dentro de seu nó pai sem iterar e comparar todos os nós filhos?
Por exemplo,
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 uma maneira melhor de determinar o índice da criança?
javascript
dom
Todos os trabalhadores são essenciais
fonte
fonte
parent.childNodes
, em vez deparent.children
?. Este último lista apenas oElements
, excluindo emText
nós específicos ... Algumas das respostas aqui, por exemplo, usandopreviousSibling
, são baseadas no uso de todos os nós filhos, enquanto outras são incomodadas apenas com crianças que sãoElement
s ... (!).childNodes
definitivamente deve ser usado em vez de.children
. As 2 principais respostas postadas fornecerão resultados diferentes, conforme você apontou.Respostas:
você pode usar a
previousSibling
propriedade para iterar de volta entre os irmãos até voltarnull
e contar quantos irmãos encontrou:Observe que em linguagens como Java, existe uma
getPreviousSibling()
função, no entanto, em JS, ela se tornou uma propriedade -previousSibling
.fonte
for (var i=0; (node=node.previousSibling); i++);
i
estará acessível..previousSibling
e.previousElementSibling
. O primeiro atinge os nós de texto, o último não.Eu gosto de usar
indexOf
para isso. ComoindexOf
está ativadoArray.prototype
eparent.children
é umNodeList
, você deve usarcall();
É meio feio, mas é um liner e usa funções com as quais qualquer desenvolvedor de javascript deve estar familiarizado.fonte
[]
cria uma instância de Array toda vez que você executa esse código, o que é menos eficiente para memória e GC do que usarArray.prototype
.[]
limpa a memória como um valor de lixo?[].indexOf
o motor é necessário criar uma instância de array apenas para acessar aindexOf
implementação no protótipo. A instância em si fica sem uso (faz GC, não é um vazamento, está apenas desperdiçando ciclos).Array.prototype.indexOf
acessa essa implementação diretamente sem alocar uma instância anônima. A diferença será insignificante em quase todas as circunstâncias, portanto, francamente, pode não valer a pena se preocupar com isso.ES6:
Explicação:
element.parentNode.children
→ Retorna os irmãos deelement
, incluindo aquele elemento.Array.from
→ Converte o construtor dechildren
em umArray
objetoindexOf
→ Você pode se inscreverindexOf
porque agora você tem umArray
objeto.fonte
Array.from
trabalhos no Internet explorercreates a new Array instance from an array-like or iterable object.
Criar uma nova instância de array apenas para encontrar um índice pode não ser eficiente em memória ou GC, dependendo da freqüência da operação, caso em que a iteração, conforme explicado na resposta aceita, seria mais ideal.ES — Shorter
O operador spread é um atalho para isso
fonte
e.parentElement.childNodes
ee.parentNode.children
?childNodes
inclui nós de texto tambémType 'NodeListOf<ChildNode>' must have a '[Symbol.iterator]()' method that returns an iterator.ts(2488)
Adicionando um (prefixado para segurança) element.getParentIndex ():
fonte
if (!Element.prototype.getParentIndex) Element.prototype.getParentIndex = function(){ /* code here */ }
? De qualquer forma, se isso for implementado no padrão no futuro, provavelmente será implementado como um getterelement.parentIndex
. Então, eu diria que a melhor abordagem seriaif(!Element.prototype.getParentIndex) Element.prototype.getParentIndex=Element.prototype.parentIndex?function() {return this.parentIndex}:function() {return Array.prototype.indexOf.call(this.parentNode.children, this)}
getParentIndex()
pode ter uma assinatura diferente da sua implementação.Eu suponho que dado um elemento onde todos os seus filhos são ordenados no documento sequencialmente, a maneira mais rápida deveria ser fazer uma pesquisa binária, comparando as posições dos elementos no documento. No entanto, conforme apresentado na conclusão, a hipótese é rejeitada. Quanto mais elementos você tiver, maior será o potencial de desempenho. Por exemplo, se você tivesse 256 elementos, então (idealmente) você só precisaria verificar apenas 16 deles! Para 65536, apenas 256! O desempenho chega à potência de 2! Veja mais números / estatísticas. Visite a Wikipedia
Então, a maneira de usá-lo é obtendo a propriedade 'parentIndex' de qualquer elemento. Por exemplo, verifique a seguinte demonstração.
Limitações
Pesquisa linear VS binária em 200 mil elementos (pode travar alguns navegadores móveis, CUIDADO!):
Pesquisa Binária
Exibir trecho de código
Pesquisa Linear para trás (`lastIndexOf`)
Exibir trecho de código
Pesquisa Linear para a frente (`indexOf`)
Exibir trecho de código
Pesquisa de contador PreviousElementSibling
Conta o número de PreviousElementSiblings para obter o parentIndex.
Exibir trecho de código
Sem Pesquisa
Para fazer o benchmarking, qual seria o resultado do teste se o navegador otimizasse a pesquisa.
Exibir trecho de código
The Conculsion
No entanto, depois de ver os resultados no Chrome, os resultados são o oposto do que era esperado. A pesquisa linear direta mais burra foi surpreendentemente 187 ms, 3850%, mais rápida do que a pesquisa binária. Evidentemente, o Chrome de alguma forma magicamente superou o
console.assert
e o otimizou, ou (de forma mais otimista) o Chrome usa internamente o sistema de indexação numérica para o DOM, e esse sistema de indexação interno é exposto por meio de otimizações aplicadasArray.prototype.indexOf
quando usado em umHTMLCollection
objeto.fonte
Use o algoritmo de pesquisa binária para melhorar o desempenho quando o nó tiver irmãos em grande quantidade.
fonte
Tive problemas com nós de texto e ele estava mostrando o índice errado. Aqui está a versão para consertar isso.
fonte
Ex
fonte
Element.prototype
? As funções parecem úteis, mas não sei o que elas fazem (mesmo que as nomeações sejam óbvias).el.group.value()
??. Meu primeiro comentário é para melhorar a qualidade da sua resposta.Você poderia fazer algo assim:
https://developer.mozilla.org/en-US/docs/Web/API/Node/parentElement
fonte
fonte