Gibt es in direktem Javascript (dh ohne Erweiterungen wie jQuery usw.) eine Möglichkeit, den Index eines untergeordneten Knotens innerhalb seines übergeordneten Knotens zu bestimmen, ohne alle untergeordneten Knoten zu durchlaufen und zu vergleichen?
Z.B,
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;
}
}
Gibt es eine bessere Möglichkeit, den Index des Kindes zu bestimmen?
javascript
dom
Alle Arbeiter sind wesentlich
quelle
quelle
parent.childNodes
, anstattparent.children
? Letzteres listet nur dieElements
, mit Ausnahme bestimmterText
Knoten, auf ... Einige der Antworten hier, z. B. usingpreviousSibling
, basieren auf der Verwendung aller untergeordneten Knoten, während andere sich nur mit Kindern beschäftigen, dieElement
... (!).childNodes
sollte auf jeden Fall anstelle von verwendet werden.children
. Die beiden am häufigsten veröffentlichten Antworten führen zu unterschiedlichen Ergebnissen, wie Sie bereits betont haben.Antworten:
Sie können die
previousSibling
Eigenschaft verwenden, um die Geschwister zu durchlaufen, bis Sie zurückkehrennull
und zählen, wie viele Geschwister Sie angetroffen haben:Bitte beachten Sie, dass es in Sprachen wie Java eine
getPreviousSibling()
Funktion gibt, in JS ist dies jedoch eine Eigenschaft geworden -previousSibling
.quelle
for (var i=0; (node=node.previousSibling); i++);
i
zugänglich..previousSibling
und.previousElementSibling
. Ersteres trifft Textknoten, letzteres nicht.Ich habe es gern benutzt
indexOf
. Weil eingeschaltetindexOf
istArray.prototype
und einparent.children
istNodeList
, muss man es verwenden.call();
Es ist irgendwie hässlich, aber es ist ein Einzeiler und verwendet Funktionen, mit denen jeder Javascript-Entwickler sowieso vertraut sein sollte.quelle
[]
jedes Mal eine Array-Instanz, wenn Sie diesen Code ausführen, was für Speicher und GC weniger effizient ist als für usingArray.prototype
.[]
Speicher nicht als Müllwert sauber?[].indexOf
die Engine auszuwerten , muss eine Array-Instanz erstellt werden, um auf dieindexOf
Implementierung des Prototyps zugreifen zu können . Die Instanz selbst wird nicht verwendet (es wird GC ausgeführt, es ist kein Leck, es werden nur Zyklen verschwendet).Array.prototype.indexOf
greift direkt auf diese Implementierung zu, ohne eine anonyme Instanz zuzuweisen. Der Unterschied wird unter fast allen Umständen vernachlässigbar sein, so dass es sich offen gesagt möglicherweise nicht lohnt, sich darum zu kümmern.ES6:
Erklärung:
element.parentNode.children
→ Gibt die Brüder vonelement
einschließlich dieses Elements zurück.Array.from
→ Wirkt den Konstruktorchildren
auf einArray
ObjektindexOf
→ Sie können sich bewerben,indexOf
weil Sie jetzt einArray
Objekt haben.quelle
Array.from
Arbeiten im Internet Explorercreates a new Array instance from an array-like or iterable object.
Erstellen einer neuen Array-Instanz, um nur einen Index zu finden, möglicherweise nicht speicher- oder GC-effizient, je nachdem, wie häufig die Operation ausgeführt wird. In diesem Fall wäre die Iteration, wie in der akzeptierten Antwort erläutert, häufiger Ideal.ES - kürzer
Der Spread-Operator ist eine Abkürzung dafür
quelle
e.parentElement.childNodes
unde.parentNode.children
?childNodes
enthält auchType 'NodeListOf<ChildNode>' must have a '[Symbol.iterator]()' method that returns an iterator.ts(2488)
Hinzufügen eines (aus Sicherheitsgründen vorangestellten) Elements.getParentIndex ():
quelle
if (!Element.prototype.getParentIndex) Element.prototype.getParentIndex = function(){ /* code here */ }
? Wenn dies in Zukunft jemals in den Standard implementiert wird, wird es wahrscheinlich als Getter-ähnliche implementiertelement.parentIndex
. Also, ich würde sagen, der beste Ansatz wäreif(!Element.prototype.getParentIndex) Element.prototype.getParentIndex=Element.prototype.parentIndex?function() {return this.parentIndex}:function() {return Array.prototype.indexOf.call(this.parentNode.children, this)}
getParentIndex()
möglicherweise eine andere Signatur hat als Ihre Implementierung.Ich gehe davon aus, dass bei einem Element, bei dem alle untergeordneten Elemente nacheinander im Dokument angeordnet sind, der schnellste Weg darin bestehen sollte, eine binäre Suche durchzuführen und die Dokumentpositionen der Elemente zu vergleichen. Wie in der Schlussfolgerung eingeführt, wird die Hypothese jedoch zurückgewiesen. Je mehr Elemente Sie haben, desto größer ist das Leistungspotenzial. Wenn Sie beispielsweise 256 Elemente hätten, müssten Sie (optimalerweise) nur 16 davon überprüfen! Für 65536 nur 256! Die Leistung wächst auf 2! Weitere Zahlen / Statistiken anzeigen. Besuchen Sie Wikipedia
Die Art und Weise, wie Sie es verwenden, besteht darin, die Eigenschaft 'parentIndex' eines beliebigen Elements abzurufen. Schauen Sie sich zum Beispiel die folgende Demo an.
Einschränkungen
Binäre VS Lineare Suche Auf 200.000 Elementen (könnte einige mobile Browser zum Absturz bringen, ACHTUNG!):
Binäre Suche
Code-Snippet anzeigen
Rückwärts (`lastIndexOf`) Lineare Suche
Code-Snippet anzeigen
Vorwärts (`indexOf`) Lineare Suche
Code-Snippet anzeigen
PreviousElementSibling Counter Search
Zählt die Anzahl der PreviousElementS Geschwister, um den parentIndex abzurufen.
Code-Snippet anzeigen
Keine Suche
Für das Benchmarking wäre das Ergebnis des Tests, wenn der Browser die Suche optimiert hätte.
Code-Snippet anzeigen
Der Zusammenstoß
Nach dem Anzeigen der Ergebnisse in Chrome sind die Ergebnisse jedoch das Gegenteil von den erwarteten Ergebnissen. Die dümmer vorwärts gerichtete lineare Suche war überraschend 187 ms, 3850%, schneller als die binäre Suche. Offensichtlich hat Chrome das auf magische Weise überlistet
console.assert
und optimiert, oder (optimistischer) Chrome verwendet intern ein numerisches Indizierungssystem für das DOM, und dieses interne Indizierungssystem wird durch die Optimierungen verfügbar gemacht, dieArray.prototype.indexOf
bei der Verwendung auf einHTMLCollection
Objekt angewendet werden.quelle
Verwenden Sie den binären Suchalgorithmus , um die Leistung zu verbessern, wenn der Knoten Geschwister mit großer Anzahl hat.
quelle
Ich hatte ein Problem mit Textknoten und es wurde ein falscher Index angezeigt. Hier ist die Version, um das Problem zu beheben.
quelle
Ex
quelle
Element.prototype
? Die Funktionen sehen nützlich aus, aber ich weiß nicht, was diese Funktionen tun (auch wenn die Namen offensichtlich sind).el.group.value()
??. Mein erster Kommentar dient dazu, die Qualität Ihrer Antwort zu verbessern.Könnten Sie so etwas tun:
https://developer.mozilla.org/en-US/docs/Web/API/Node/parentElement
quelle
quelle