javascript firefox dom greasemonkey

javascript - Id. De elemento único, incluso si el elemento no tiene uno



getelementsbyclassname (13)

''Creo'' que acabo de resolver un problema similar a esto. Sin embargo, estoy usando jQuery en un entorno DOM del navegador.

var objA = $ ("selector a algún elemento dom"); var objB = $ ("selector a algún otro elemento dom");

if (objA [0] === objB [0]) {// ¡EXCELENTE! los dos objetos apuntan exactamente al mismo domdom}

Estoy escribiendo un script de GreaseMonkey donde estoy iterando a través de un montón de elementos. Para cada elemento, necesito una ID de cadena que pueda usar para hacer referencia a ese elemento más adelante. El elemento en sí no tiene un atributo de id , y no puedo modificar el documento original para darle uno (aunque puedo hacer cambios DOM en mi script). No puedo almacenar las referencias en mi script porque cuando las necesito, el script de GreaseMonkey se habrá salido del alcance. ¿Hay alguna forma de obtener una ID "interna" que usa el navegador, por ejemplo? Una solución solo para Firefox está bien; una solución de navegador cruzado que podría aplicarse en otros escenarios sería increíble.

Editar:

  • Si el script de GreaseMonkey está fuera del alcance, ¿cómo hace referencia a los elementos más adelante? La secuencia de comandos GreaseMonkey está agregando eventos a los objetos DOM. No puedo almacenar las referencias en una matriz u otro mecanismo similar porque cuando el evento se dispara, la matriz se habrá ido porque la secuencia de comandos de GreaseMonkey se habrá salido del alcance. Por lo tanto, el evento necesita alguna forma de conocer la referencia de elemento que tenía el script cuando se adjuntó el evento. Y el elemento en cuestión no es al que está unido.

  • ¿No puedes usar una propiedad personalizada en el elemento? Sí, pero el problema está en la búsqueda. Tendría que recurrir a iterar a través de todos los elementos buscando el que tiene esa propiedad personalizada establecida en el ID deseado. Eso funcionaría, claro, pero en documentos grandes podría llevar mucho tiempo. Estoy buscando algo donde el navegador pueda hacer el trabajo de búsqueda.

  • Espera, ¿puedes o no puedes modificar el documento? No puedo modificar el documento fuente, pero puedo hacer cambios DOM en el script. Voy a aclarar en la pregunta.

  • ¿No puedes usar cierres? Los closes se pusieron a trabajar, aunque inicialmente pensé que no lo harían. Ver mi publicación posterior.

Suena como la respuesta a la pregunta: "¿Hay algún ID de navegador interno que pueda usar?" no es."


El cierre es el camino a seguir. De esta forma tendrá una referencia exacta del elemento que incluso sobrevivirá a algunos cambios de DOM.

Ejemplo para aquellos que no conocen cierres:

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

Si tuvieras que guardarlo en una cookie, te recomiendo calcular XPath para ello (por ejemplo, caminar hasta el DOM contando hermanos anteriores hasta que encuentres un elemento con una ID y terminarás con algo como [@id=foo]/div[4]/p[2]/a ).

XPointer es la solución del W3C a ese problema.


En javascript, puede adjuntar un campo de ID personalizado al nodo

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

Es un poco complicado, pero le dará a cada nodo una identificación que puedes usar. Por supuesto, document.getElementById() no le prestará atención.


La respuesta es no, no hay una identificación interna a la que pueda acceder. Opera e IE (¿quizás Safari?) .sourceIndex (que cambia si DOM lo hace) pero Firefox no tiene nada de esto.

Puede simular el índice de origen generando Xpath a un nodo dado o encontrando el índice del nodo de document.getElementsByTagName(''*'') que siempre devolverá los elementos en orden de origen.

Todo esto requiere un archivo completamente estático, por supuesto. Los cambios en DOM romperán la búsqueda.

Lo que no entiendo es cómo se pueden perder referencias a nodos pero no a identificaciones internas (teóricas)? O cierres y asignaciones funcionan o no. ¿O me estoy perdiendo algo?


OK, no hay un ID asociado al elemento DOM automáticamente. DOM tiene una estructura jerárquica de elementos que es la información principal. Desde esta perspectiva, puede asociar datos a elementos DOM con jQuery o jQLite. Puede resolver algunos problemas cuando tiene que vincular datos personalizados a elementos.


Puede establecer el atributo id a un valor calculado. Hay una función en la biblioteca de prototipos que puede hacer esto por usted.

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

Mi biblioteca de JavaScript favorita es jQuery. Desafortunadamente jQuery no tiene una función como identificar. Sin embargo, aún puede establecer el atributo id en un valor que genere usted mismo.

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

Aquí hay un fragmento parcial de documentos de jQuery que establece el id para los divs en función de la posición en la página:

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


Puede generar un identificador único y estable para cualquier nodo dado en un DOM con la siguiente función:

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

Esto creará identificadores como doc/0 , doc/0/0 , doc/0/0 , doc/0/0 , doc/0/0 para una estructura como esta:

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

También hay algunas optimizaciones y cambios que puede realizar, por ejemplo:

  • En el ciclo while, break cuando ese node tenga un atributo que sabes que es único, por ejemplo @id

  • No reverse() las pieces , actualmente solo está ahí para parecerse más a la estructura DOM de la que se generan los ID.

  • No incluya el doc la primera piece si no necesita un identificador para el nodo del documento

  • Guarde el identificador en el nodo de alguna manera y reutilice ese valor para los nodos secundarios para evitar tener que recorrer todo el camino nuevamente en el árbol.

  • Si está escribiendo estos identificadores en XML, use otro carácter de concatenación si el atributo que está escribiendo está restringido.


Si no está modificando el DOM, puede obtenerlos por orden indexado:

(Ejemplo de prototipo )

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

Podría recorrer todos los nodos y darles un nombre de clase único que luego podría seleccionar fácilmente.


Si puedes escribir en el DOM (estoy seguro de que puedes). Yo resolvería esto así:

Tener una función de retorno o generar una ID:

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

Use esto para obtener identificaciones según sea necesario:

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

De esta forma, no tendrá que preocuparse por cómo se ve el HTML cuando el servidor se lo entregue.


También puede usar pguid (identificador único de página) para la generación de identificador único:

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


Un poco confundido por la redacción de su pregunta: usted dice que "necesita una ID de cadena que [usted] puede usar para hacer referencia a ese elemento más adelante", pero que "no puede almacenar las referencias en [su] secuencia de comandos porque cuando [ usted] los necesita, el script de GreaseMonkey se habrá salido del alcance ".

Si el guión se ha salido del alcance, ¿cómo los está haciendo referencia más adelante?

Voy a ignorar el hecho de que estoy confundido por lo que está viendo y le digo que escribo scripts de Greasemonkey con bastante frecuencia y puedo modificar los elementos DOM a los que accedo para darles una propiedad de identificación. Este es el código que puede usar para obtener un valor pseudo-único para uso temporal:

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;

Eso funciona para mí, simplemente lo probé en un script de Greasemonkey.

ACTUALIZACIÓN: Los cierres son el camino a seguir, personalmente, como un desarrollador de JavaScript duro, no sé cómo no pensaste en esos inmediatamente. :)

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

Ahora, myDomElement es uno de los elementos que aparentemente, de acuerdo con su descripción, ya tiene (ya que estaba pensando en agregarle una ID, o lo que sea).

Tal vez si publica un ejemplo de lo que está tratando de hacer, sería más fácil ayudarle, suponiendo que esto no ocurra.


Utilice las propiedades de posición y / o mouse del elemento para generar una ID única.


ACTUALIZACIÓN: Los cierres son de hecho la respuesta. Entonces, después de jugar un poco más, descubrí por qué los cierres eran inicialmente problemáticos y cómo solucionarlos. Lo complicado con un cierre es que debes tener cuidado al recorrer los elementos para no terminar con todos tus cierres haciendo referencia al mismo elemento. Por ejemplo, esto no funciona:

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

Pero esto hace:

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

De todos modos, decidí no seleccionar una respuesta porque la pregunta tenía dos respuestas: 1) No, no hay ID internas que pueda usar; 2) deberías usar cierres para esto. Así que simplemente voté por encima de las primeras personas para decir si había identificaciones internas o quién recomendaba la generación de identificaciones, más cualquiera que mencionara los cierres. ¡Gracias por la ayuda!