Question

J'écris un script GreaseMonkey dans lequel je parcours plusieurs éléments. Pour chaque élément, j'ai besoin d'un ID de chaîne que je peux utiliser pour référencer cet élément ultérieurement. L'élément lui-même n'a pas d'attribut id et je ne peux pas modifier le document d'origine pour lui en donner un (bien que je puisse apporter des modifications DOM dans mon script). Je ne peux pas stocker les références dans mon script car, lorsque j'en aurai besoin, le script GreaseMonkey lui-même sera hors de portée. Existe-t-il un moyen d’aboutir à un "interne"? Identifiant utilisé par le navigateur, par exemple? Une solution réservée à Firefox suffit. une solution inter-navigateur qui pourrait être appliquée dans d'autres scénarios serait géniale.

Modifier:

  • Si le script GreaseMonkey est hors de portée, comment allez-vous référencer les éléments plus tard? Le script GreaseMonkey ajoute des événements aux objets DOM. Je ne peux pas stocker les références dans un tableau ni dans un autre mécanisme similaire car, lorsque l'événement se déclenche, le tableau disparaîtra car le script GreaseMonkey sera hors de portée. L'événement a donc besoin d'un moyen de connaître la référence à l'élément que le script avait quand l'attachement à l'événement. Et l'élément en question n'est pas celui auquel il est attaché.

  • Ne pouvez-vous pas simplement utiliser une propriété personnalisée sur l'élément? Oui, mais le problème réside dans la recherche. Je devrais recourir à tous les éléments à la recherche de celui qui a cette propriété personnalisée définie à l'identifiant souhaité. Cela fonctionnerait, bien sûr, mais dans les gros documents, cela prendrait beaucoup de temps. Je cherche quelque chose où le navigateur peut effectuer le travail de recherche de grunts.

  • Attendez, pouvez-vous ou non modifier le document? Je ne peux pas modifier le document source, mais je peux apporter des modifications DOM dans le script. Je vais clarifier la question.

  • Ne pouvez-vous pas utiliser des fermetures? Les Closuses se sont avérés efficaces, bien que, au départ, je pensais qu'ils ne le feraient pas. Voir mon post ultérieur.

Cela ressemble à la réponse à la question: "Existe-t-il un identifiant de navigateur interne que je pourrais utiliser?" est "N °"

Était-ce utile?

La solution 4

UPDATE: Les fermetures sont la solution. Ainsi, après avoir joué un peu plus avec cela, j'ai compris pourquoi les fermetures étaient initialement problématiques et comment y remédier. La difficulté avec une fermeture est que vous devez faire attention lorsque vous parcourez les éléments pour ne pas vous retrouver avec toutes vos fermetures référençant le même élément. Par exemple, cela ne fonctionne pas:

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)
}

Mais ceci fait:

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)
}

Quoi qu'il en soit, j'ai décidé de ne pas sélectionner une réponse car la question comportait deux réponses: 1) Non, vous ne pouvez utiliser aucun identifiant interne. 2) vous devriez utiliser des fermetures pour cela. J'ai donc simplement invité les premières personnes à dire s'il existait des identifiants internes ou ceux qui recommandaient de générer des identifiants, ainsi que toute personne ayant mentionné des fermetures. Merci pour l'aide!

Autres conseils

La réponse est non, il n'y a pas d'identifiant interne auquel vous pouvez accéder. Opera et IE (peut-être Safari?) Supportent .sourceIndex (ce qui change si DOM le fait) mais Firefox n’a rien de ce genre.

Vous pouvez simuler source-index en générant Xpath sur un nœud donné ou en recherchant l'index du document.getElementsByTagName ('*') qui renverra toujours les éléments dans l'ordre source.

Tout cela nécessite bien sûr un fichier complètement statique. Les modifications apportées à DOM interrompront la recherche.

Ce que je ne comprends pas, c'est comment vous pouvez perdre des références aux nœuds mais pas aux identifiants internes (théoriques)? Les fermetures et les affectations fonctionnent ou ne fonctionnent pas. Ou est-ce que je manque quelque chose?

La fermeture est la voie à suivre. De cette façon, vous aurez une référence exacte à l’élément qui survivra même à un remaniement de DOM.

Exemple pour ceux qui ne connaissent pas les fermetures:

var saved_element = findThatDOMNode();

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

Si vous deviez le stocker dans un cookie, je vous recommande de l'installer sous XPath (par exemple, parcourez le DOM en comptant le nombre de frères et sœurs précédents jusqu'à ce que vous trouviez un élément avec un ID et vous vous retrouverez avec quelque chose comme [@ id = toto] / div [4] / p [2] / a ).

XPointer est la solution du W3C à ce problème.

Un peu gêné par le libellé de votre question - vous dites que vous "avez besoin d'un identifiant de chaîne que [vous] pouvez utiliser pour référencer cet élément ultérieurement," mais que vous "ne pouvez pas stocker les références dans [votre] script car, si vous en avez besoin, le script GreaseMonkey lui-même est hors de portée."

Si le script est hors de portée, comment allez-vous le référencer plus tard?!

Je vais ignorer le fait que je vous laisse perplexe et vous dire que j'écris des scripts Greasemonkey assez souvent et que peut modifier les éléments DOM auxquels j'ai accès pour leur attribuer un ID. propriété. C’est le code que vous pouvez utiliser pour obtenir une valeur pseudo-unique à usage temporaire:

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;

Cela fonctionne pour moi, je viens de le tester moi-même dans un script Greasemonkey.

MISE À JOUR: Les fermetures sont la solution. Personnellement, en tant que développeur JavaScript fondamental, je ne sais pas comment vous n'y avez pas pensé immédiatement. . :)

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);

Maintenant, myDomElement est l'un des éléments que vous avez apparemment déjà, d'après votre description, autour (depuis que vous songez à lui ajouter un identifiant, ou autre chose).

Peut-être que si vous publiez un exemple de ce que vous essayez de faire, il serait plus facile de vous aider, en supposant que ce ne soit pas le cas.

Si vous pouvez écrire dans le DOM (je suis sûr que vous le pouvez). Je voudrais résoudre ceci comme ceci:

Demander à une fonction de retourner ou de générer un identifiant:

//(function () {

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

//})();

Utilisez ceci pour obtenir les identifiants nécessaires:

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

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

De cette façon, vous n'avez pas à vous soucier de l'apparence du code HTML lorsque le serveur vous le transmet.

Si vous ne modifiez pas le DOM, vous pouvez tous les obtenir par ordre indexé:

( exemple de prototype )

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

Vous pouvez parcourir tous les nœuds et leur attribuer un nom de classe unique que vous pourrez ensuite sélectionner facilement.

Vous pouvez définir l'attribut id sur une valeur calculée. Il existe une fonction dans la bibliothèque de prototypes qui peut le faire pour vous.

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

Ma bibliothèque javascript préférée est jQuery. Malheureusement, jQuery n’a pas une fonction comme identifier. Cependant, vous pouvez toujours définir l'attribut id sur une valeur que vous générez vous-même.

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

Voici un extrait partiel de docs jQuery qui définit l'identifiant des div en fonction de la position dans la page:

  $(document).ready(function(){

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

Vous pouvez également utiliser pguid (identifiant unique de page) pour la génération d'identifiant unique:

 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

Utilisez les propriétés de souris et / ou de position de l'élément pour générer un identifiant unique.

Vous pouvez générer un identifiant unique et stable pour tout nœud donné dans un DOM avec la fonction suivante:

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('/');
}

Ceci créera des identifiants tels que doc / 0 , doc / 0/0 , doc / 0/1 , doc / 0/1/0 , doc / 0/1/1 pour une structure semblable à celle-ci:

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

Vous pouvez également apporter quelques optimisations et modifications, par exemple:

  • Dans la boucle while , rompt lorsque ce nœud a un attribut que vous savez être unique, par exemple . @id

  • Pas reverse () les morceaux , actuellement, il est juste là pour ressembler davantage à la structure DOM à partir de laquelle les ID sont générés

  • N'incluez pas la première pièce doc si vous n'avez pas besoin d'un identifiant pour le noeud du document

  • Enregistrez l’identifiant sur le nœud d’une manière ou d’une autre et réutilisez cette valeur pour les nœuds enfants afin d’éviter de remonter dans l’arbre.

  • Si vous écrivez ces identificateurs dans XML, utilisez un autre caractère de concaténation si l'attribut que vous écrivez est restreint.

En javascript, vous pouvez associer un champ d'identifiant personnalisé au nœud

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

// store myId

C'est un peu de bidouille, mais cela donnera à chaque nœud un identifiant que vous pouvez utiliser. Bien sûr, document.getElementById () n'y fera pas attention.

Je pense que je viens de résoudre un problème similaire à celui-ci. Cependant, j'utilise jQuery dans un environnement DOM de navigateur.

var objA = $ ("sélecteur sur un élément dom"); var objB = $ ("sélecteur sur un autre élément dom");

if (objA [0] === objB [0]) {   //GÉNIAL! les deux objets désignent exactement le même nœud dom }

OK, il n'y a pas d'identifiant associé à l'élément DOM automatiquement. DOM a une structure hiérarchique d’éléments qui constitue l’information principale. Dans cette perspective, vous pouvez associer des données à des éléments DOM avec jQuery ou jQLite. Cela peut résoudre certains problèmes lorsque vous devez lier des données personnalisées à des éléments.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top