Unique element ID, even if element doesn't hav

2019-01-22 11:59发布

I'm writing a GreaseMonkey script where I'm iterating through a bunch of elements. For each element, I need a string ID that I can use to reference that element later. The element itself doesn't have an id attribute, and I can't modify the original document to give it one (although I can make DOM changes in my script). I can't store the references in my script because when I need them, the GreaseMonkey script itself will have gone out of scope. Is there some way to get at an "internal" ID that the browser uses, for example? A Firefox-only solution is fine; a cross-browser solution that could be applied in other scenarios would be awesome.

Edit:

  • If the GreaseMonkey script is out of scope, how are you referencing the elements later? They GreaseMonkey script is adding events to DOM objects. I can't store the references in an array or some other similar mechanism because when the event fires, the array will be gone because the GreaseMonkey script will have gone out of scope. So the event needs some way to know about the element reference that the script had when the event was attached. And the element in question is not the one to which it is attached.

  • Can't you just use a custom property on the element? Yes, but the problem is on the lookup. I'd have to resort to iterating through all the elements looking for the one that has that custom property set to the desired id. That would work, sure, but in large documents it could be very time consuming. I'm looking for something where the browser can do the lookup grunt work.

  • Wait, can you or can you not modify the document? I can't modify the source document, but I can make DOM changes in the script. I'll clarify in the question.

  • Can you not use closures? Closuses did turn out to work, although I initially thought they wouldn't. See my later post.

It sounds like the answer to the question: "Is there some internal browser ID I could use?" is "No."

13条回答
Summer. ? 凉城
2楼-- · 2019-01-22 12:38

You can generate a stable, unique identifier for any given node in a DOM with the following function:

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

This will create identifiers such as doc/0, doc/0/0, doc/0/1, doc/0/1/0, doc/0/1/1 for a structure like this one:

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

There are also a few optimisations and changes you can make, for example:

  • In the while loop, break when that node has an attribute you know to be unique, for example @id

  • Not reverse() the pieces, currently it is just there to look more like the DOM structure the ID's are generated from

  • Not include the first piece doc if you don't need an identifier for the document node

  • Save the identifier on the node in some way, and reuse that value for child nodes to avoid having to traverse all the way up the tree again.

  • If you're writing these identifiers back to XML, use another concatenation character if the attribute you're writing is restricted.

查看更多
登录 后发表回答