it-swarm.com.de

Eindeutige Element-ID, auch wenn das Element keine hat

Ich schreibe ein GreaseMonkey-Skript, in dem ich eine Reihe von Elementen durchlaufe. Für jedes Element benötige ich eine Zeichenfolgen-ID, mit der ich später auf dieses Element verweisen kann. Das Element selbst hat kein id-Attribut, und ich kann das Originaldokument nicht so ändern, dass es eines enthält (obwohl ich DOM-Änderungen in meinem Skript vornehmen kann). Ich kann die Referenzen nicht in meinem Skript speichern, da das GreaseMonkey-Skript selbst den Gültigkeitsbereich verlassen hat, wenn ich sie benötige. Gibt es eine Möglichkeit, an eine "interne" ID zu gelangen, die der Browser beispielsweise verwendet? Eine reine Firefox-Lösung ist in Ordnung. Eine browserübergreifende Lösung, die in anderen Szenarien angewendet werden könnte, wäre fantastisch.

Bearbeiten:

  • Wenn das GreaseMonkey-Skript außerhalb des Gültigkeitsbereichs liegt, wie verweisen Sie die Elemente später? They GreaseMonkey-Skript fügt DOM-Objekten Ereignisse hinzu. Ich kann die Referenzen nicht in einem Array oder einem ähnlichen Mechanismus speichern, da das Array beim Auslösen des Ereignisses nicht mehr vorhanden ist, da das GreaseMonkey-Skript den Gültigkeitsbereich verlassen hat. Das Ereignis muss also in gewisser Weise über die Elementreferenz informiert werden, die das Skript hatte, als das Ereignis angehängt wurde. Und das fragliche Element ist nicht dasjenige, an das es gebunden ist.

  • Können Sie nicht einfach eine benutzerdefinierte Eigenschaft für das Element verwenden? Ja, aber das Problem liegt in der Suche. Ich müsste darauf zurückgreifen, alle Elemente zu durchlaufen, um nach dem Element zu suchen, dessen benutzerdefinierte Eigenschaft auf die gewünschte ID festgelegt ist. Das würde zwar funktionieren, aber in großen Dokumenten kann es sehr zeitaufwändig sein. Ich bin auf der Suche nach etwas, wo der Browser die Suche erledigen kann.

  • Warten Sie, können Sie oder können Sie das Dokument nicht ändern? Ich kann das Quelldokument nicht ändern, aber ich kann DOM-Änderungen im Skript vornehmen. Ich werde in der Frage klären.

  • Können Sie Verschlüsse nicht verwenden? Closuses erwies sich als funktionierend, obwohl ich anfangs dachte, dass sie dies nicht tun würden. Siehe meinen späteren Beitrag.

Es klingt wie die Antwort auf die Frage: "Gibt es eine interne Browser-ID, die ich verwenden könnte?" ist "Nein".

29

UPDATE: Abschlüsse sind in der Tat die Antwort. Nachdem ich noch ein bisschen damit herumgespielt hatte, fand ich heraus, warum Verschlüsse anfangs problematisch waren und wie man sie repariert. Das Schwierige an einem Closure ist, dass Sie beim Durchlaufen der Elemente vorsichtig sein müssen, damit nicht alle Closures auf dasselbe Element verweisen. Zum Beispiel funktioniert das nicht:

for (var i = 0; i < elements.length; i++) {
    var element = elements[i];
    var button = document.createElement("button");
    button.addEventListener("click", function(ev) {
        // do something with element here
    }, false)
}

Aber das macht:

var buildListener = function(element) {
    return function(ev) {
        // do something with event here
    };
};

for (var i = 0; i < elements.length; i++) {
    var element = elements[i];
    var button = document.createElement("button");
    button.addEventListener("click", buildListener(element), false)
}

Wie auch immer, ich habe mich entschieden, keine Antwort auszuwählen, da die Frage zwei Antworten hatte: 1) Nein, es gibt keine internen IDs, die Sie verwenden können; 2) Verwenden Sie hierfür Verschlüsse. Also habe ich einfach die ersten Leute dazu gebracht, zu sagen, ob es interne IDs gibt oder wer empfohlen hat, IDs zu generieren, sowie jeden, der Schließungen erwähnt. Danke für die Hilfe!

5

Die Antwort ist nein, es gibt keine interne ID, auf die Sie zugreifen können. Opera und IE (vielleicht Safari?) Unterstützen .sourceIndex (was sich ändert, wenn DOM es tut), aber Firefox hat nichts von dieser Art.

Sie können den Quellindex simulieren, indem Sie Xpath für einen bestimmten Knoten generieren oder den Index des Knotens aus document.getElementsByTagName('*') ermitteln, der die Elemente immer in der Quellreihenfolge zurückgibt.

All dies erfordert natürlich eine vollständig statische Datei. Änderungen an DOM unterbrechen die Suche.

Was ich nicht verstehe, ist, wie Sie Verweise auf Knoten verlieren können, aber nicht auf (theoretische) interne IDs? Entweder funktionieren Abschlüsse und Zuweisungen, oder sie funktionieren nicht. Oder fehlt mir etwas?

7
Borgar

Ein bisschen verwirrt durch den Wortlaut Ihrer Frage - Sie sagen, dass Sie "eine Zeichenfolgen-ID benötigen, mit der [Sie] später auf dieses Element verweisen können", aber dass Sie "die Verweise nicht in [Ihrem] Skript speichern können, weil wenn [ Wenn Sie sie brauchen, wird das GreaseMonkey-Skript selbst den Rahmen verlassen haben. "

Wenn das Skript den Gültigkeitsbereich verlassen hat, wie verweisen Sie dann später darauf ?!

Ich werde die Tatsache ignorieren, dass ich verwirrt bin von dem, was Sie vorhaben, und Ihnen sagen, dass ich ziemlich oft Greasemonkey-Skripte schreibe und kann die DOM-Elemente, auf die ich zugreife, modifiziere, um ihnen eine ID-Eigenschaft zu verleihen. Mit diesem Code können Sie einen pseudo-eindeutigen Wert für die temporäre Verwendung abrufen:

var PseudoGuid = new (function() {
    this.empty = "00000000-0000-0000-0000-000000000000";
    this.GetNew = function() {
        var fourChars = function() {
            return (((1 + Math.random()) * 0x10000)|0).toString(16).substring(1).toUpperCase();
        }
        return (fourChars() + fourChars() + "-" + fourChars() + "-" + fourChars() + "-" + fourChars() + "-" + fourChars() + fourChars() + fourChars());
    };
})();

// usage example:
var tempId = PseudoGuid.GetNew();
someDomElement.id = tempId;

Das funktioniert bei mir, ich habe es gerade selbst in einem Greasemonkey-Skript getestet.


UPDATE: Closures sind der richtige Weg - persönlich, als Hardcore-JavaScript-Entwickler, weiß ich nicht, wie Sie nicht an diese sofort denken. :)

myDomElement; // some DOM element we want later reference to

someOtherDomElement.addEventListener("click", function(e) {
   // because of the closure, here we have a reference to myDomElement
   doSomething(myDomElement);
}, false);

Nun, myDomElement ist eines der Elemente, über die Sie Ihrer Beschreibung nach offenbar bereits verfügen (da Sie darüber nachgedacht haben, eine ID hinzuzufügen, oder was auch immer).

Wenn Sie ein Beispiel für das posten, was Sie versuchen, ist es möglicherweise einfacher, Ihnen zu helfen, sofern dies nicht der Fall ist.

6
Jason Bunting

Abschluss ist der richtige Weg. Auf diese Weise haben Sie einen genauen Verweis auf das Element, das sogar ein Mischen von DOM überlebt.

Beispiel für diejenigen, die Verschlüsse nicht kennen:

var saved_element = findThatDOMNode();

document.body.onclick = function() 
{
   alert(saved_element); // it's still there!
}

Wenn Sie es in einem Cookie speichern mussten, empfehle ich, XPath dafür zu berechnen (z. B. gehen Sie das DOM hoch und zählen Sie die vorherigen Geschwister, bis Sie ein Element mit einer ID finden und am Ende etwas wie [@id=foo]/div[4]/p[2]/a erhalten) .

XPointer ist W3Cs Lösung für dieses Problem.

6
Kornel

Wenn Sie können ins DOM schreiben (ich bin sicher, dass Sie das können). Ich würde das so lösen:

Lassen Sie eine Funktion zurückgeben oder generieren Sie eine ID:

//(function () {

  var idCounter = new Date().getTime();
  function getId( node ) {
    return (node.id) ? node.id : (node.id = 'tempIdPrefix_' + idCounter++ );
  }

//})();

Verwenden Sie diese Option, um die erforderlichen IDs abzurufen:

var n = document.getElementById('someid');
getId(n);  // returns "someid"

var n = document.getElementsByTagName('div')[1];
getId(n);  // returns "tempIdPrefix_1224697942198"

Auf diese Weise brauchen Sie sich keine Gedanken darüber zu machen, wie der HTML-Code aussieht, wenn der Server ihn Ihnen übergibt.

4
Borgar

Wenn Sie das DOM nicht ändern, können Sie sie alle in indizierter Reihenfolge abrufen:

( Prototyp Beispiel)

myNodes = document.body.descendants()
alert(document.body.descendants()[1].innerHTML)

Sie können alle Knoten durchlaufen und ihnen einen eindeutigen Klassennamen geben, den Sie später leicht auswählen können.

Sie können das ID-Attribut auf einen berechneten Wert festlegen. In der Prototypenbibliothek gibt es eine Funktion, die dies für Sie erledigen kann.

http://www.prototypejs.org/api/element/identify

Meine Lieblings-Javascript-Bibliothek ist jQuery. Leider hat jQuery keine Funktion wie identifizieren. Sie können das ID-Attribut jedoch weiterhin auf einen Wert setzen, den Sie selbst generieren.

http://docs.jquery.com/Attributes/attr#keyfn

Hier ist ein Teilausschnitt aus jQuery-Dokumenten, der die ID für divs basierend auf der Position auf der Seite festlegt:

  $(document).ready(function(){

    $("div").attr("id", function (arr) {
          return "div-id" + arr;
        });
  });
2
Michael

Mit der folgenden Funktion können Sie einen stabilen, eindeutigen Bezeichner für einen beliebigen Knoten in einem DOM generieren:

function getUniqueKeyForNode (targetNode) {
    const pieces = ['doc'];
    let node = targetNode;

    while (node && node.parentNode) {
        pieces.Push(Array.prototype.indexOf.call(node.parentNode.childNodes, node));
        node = node.parentNode
    }

    return pieces.reverse().join('/');
}

Dadurch werden Bezeichner wie doc/0, doc/0/0, doc/0/1, doc/0/1/0, doc/0/1/1 für eine Struktur wie diese erstellt:

<div>
    <div />
    <div>
        <div />
        <div />
    </div>
</div>

Es gibt auch einige Optimierungen und Änderungen, die Sie vornehmen können, zum Beispiel:

  • In der while-Schleife break, wenn diese node ein Attribut hat, von dem Sie wissen, dass es eindeutig ist, z. B. @id

  • Nicht reverse() the pieces, derzeit sieht es nur so aus wie die DOM-Struktur, aus der die IDs generiert werden

  • Geben Sie nicht die erste piecedoc an, wenn Sie keinen Bezeichner für den Dokumentknoten benötigen

  • Speichern Sie den Bezeichner auf irgendeine Weise auf dem Knoten, und verwenden Sie diesen Wert für untergeordnete Knoten erneut, um zu vermeiden, dass Sie den gesamten Baum erneut durchlaufen müssen.

  • Wenn Sie diese Bezeichner zurück in XML schreiben, verwenden Sie ein anderes Verkettungszeichen, wenn das Attribut, das Sie schreiben, eingeschränkt ist.

1
wybe

Sie können pguid (page-unique identifier) ​​auch zur Generierung eindeutiger Bezeichner verwenden:

 pguid = b9j.pguid.next() // A unique id (suitable for a DOM element)
                          // is generated
                          // Something like "b9j-pguid-20a9ff-0"
 ...
 pguid = b9j.pguid.next() // Another unique one... "b9j-pguid-20a9ff-1"

 // Build a custom generator
 var sequence = new b9j.pguid.Sequence({ namespace: "frobozz" })
 pguid = sequence.next() "frobozz-c861e1-0"

http://appengine.bravo9.com/b9j/documentation/pguid.html

1
Robert Krimen

Verwenden Sie die Maus- und/oder Positionseigenschaften des Elements, um eine eindeutige ID zu generieren.

1
Paul Tierney

Ich glaube, ich habe gerade ein ähnliches Problem gelöst. Ich verwende jedoch jQuery in einer Browser-DOM-Umgebung.

var objA = $ ("Selektor für ein dom-Element"); var objB = $ ("Selektor für ein anderes dom-Element");

if (objA [0] === objB [0]) {// GREAT! Die beiden Objekte verweisen auf genau denselben dom-Knoten.}

0
Tom Carnell

In JavaScript können Sie dem Knoten ein benutzerdefiniertes ID-Feld hinzufügen

if(node.id) {
  node.myId = node.id;
} else {
  node.myId = createId();
}

// store myId

Es ist ein bisschen Hack, aber es gibt jedem Knoten eine ID, die Sie verwenden können. Natürlich wird document.getElementById() nicht darauf achten.

0
sblundy

OK, dem DOM-Element ist keine ID automatisch zugeordnet. DOM hat eine hierarchische Struktur von Elementen, die die Hauptinformation darstellt. Aus dieser Perspektive können Sie Daten mit DOM-Elementen verknüpfen mit jQuery oder jQLite. Es kann einige Probleme lösen, wenn Sie benutzerdefinierte Daten an Elemente binden müssen.

0
kisp