我正在编写一个GreaseMonkey脚本,我正在迭代一堆元素。对于每个元素,我需要一个字符串ID,以后我可以用它来引用该元素。元素本身没有id
属性,我无法修改原始文档给它一个(虽然我可以在我的脚本中进行DOM更改)。我无法在我的脚本中存储引用,因为当我需要它们时,GreaseMonkey脚本本身将超出范围。例如,有没有办法获得浏览器使用的“内部”ID?只有Firefox的解决方案很好;可以在其他场景中应用的跨浏览器解决方案非常棒。
编辑:
如果GreaseMonkey脚本超出范围,您以后如何引用这些元素?他们GreaseMonkey脚本正在向DOM对象添加事件。我无法将引用存储在数组或其他类似的机制中,因为当事件触发时,数组将会消失,因为GreaseMonkey脚本将超出范围。因此,事件需要某种方式来了解脚本在附加事件时所具有的元素引用。并且所讨论的元素不是它附加的元素。
您不能只在元素上使用自定义属性吗?是的,但问题出在查找上。我不得不求助于遍历所有元素,寻找将自定义属性设置为所需id的元素。那肯定会有用,但在大型文档中它可能非常耗时。我正在寻找浏览器可以进行查找工作的东西。
等等,您能否或不能修改文档?我无法修改源文档,但我可以在脚本中进行DOM更改。我会在问题中澄清。
你能不能使用闭包吗?虽然我最初认为他们不会这样做但Closuses确实有效。见我后来的帖子。
这听起来像是问题的答案:“我可以使用一些内部浏览器ID吗?”是“不。”
答案 0 :(得分:7)
答案是否定的,没有可以访问的内部ID。 Opera和IE(可能是Safari?)支持.sourceIndex
(如果DOM有,它会改变)但Firefox没有这种类型。
您可以通过生成给定节点的Xpath或从document.getElementsByTagName('*')
查找节点的索引来模拟源索引,该节点将始终以源顺序返回元素。
所有这些当然需要一个完全静态的文件。对DOM的更改将破坏查找。
我不明白你如何放松对节点的引用而不是(理论上的)内部id?关闭和分配工作或他们不工作。或者我错过了什么?
答案 1 :(得分:6)
你的问题的措辞有点困惑 - 你说你需要一个[你]可以用来引用该元素的字符串ID,“但你”不能在[你的]脚本中存储引用因为当[你]需要它们时,GreaseMonkey脚本本身就会超出范围。“
如果脚本超出范围,那么以后如何引用它们?!
我将忽略这样一个事实,即我对你所得到的内容感到困惑,并告诉你我经常编写Greasemonkey脚本,可以修改我访问的DOM元素,为它们提供一个ID属性。这是可用于获取临时使用的伪唯一值的代码:
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;
这对我有用,我自己用Greasemonkey脚本测试了它。
更新:关闭是可行的方法 - 就个人而言,作为一名核心JavaScript开发人员,我不知道你如何立即想到这些。 :)
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);
现在,myDomElement
是您显然已经拥有的元素之一(因为您正在考虑为其添加ID,或其他任何内容)。
也许如果你发布一个你想要做的事情的例子,假设不这样做会更容易帮助你。
答案 2 :(得分:6)
关闭是要走的路。通过这种方式,您可以准确地引用即使在DOM的一些改组中存活的元素。
那些不知道闭包的例子:
var saved_element = findThatDOMNode();
document.body.onclick = function()
{
alert(saved_element); // it's still there!
}
如果你必须将它存储在一个cookie中,那么我建议为它计算XPath(例如,沿着DOM计算以前的兄弟姐妹,直到找到带有ID的元素,你最终会得到它像[@id=foo]/div[4]/p[2]/a
)之类的东西。
XPointer是W3C解决该问题的方法。
答案 3 :(得分:5)
更新:闭包确实是答案。所以在摆弄它之后,我想出了为什么闭包最初有问题以及如何修复它。关闭闭包的棘手问题是,在遍历元素时必须小心,不要以所有闭包引用相同的元素结束。例如,这不起作用:
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)
}
但这样做:
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)
}
无论如何,我决定不选择一个答案,因为问题有两个答案:1)不,你可以使用没有内部ID; 2)你应该使用闭包。所以我只是向第一个人投票说出是否有内部ID或谁建议生成ID,以及任何提到闭包的人。谢谢你的帮助!
答案 4 :(得分:4)
如果可以写入DOM(我相信你可以)。我会这样解决这个问题:
让函数返回或生成ID:
//(function () {
var idCounter = new Date().getTime();
function getId( node ) {
return (node.id) ? node.id : (node.id = 'tempIdPrefix_' + idCounter++ );
}
//})();
使用它来根据需要获取ID:
var n = document.getElementById('someid');
getId(n); // returns "someid"
var n = document.getElementsByTagName('div')[1];
getId(n); // returns "tempIdPrefix_1224697942198"
这样,您无需担心服务器交给您时HTML的样子。
答案 5 :(得分:3)
如果你没有修改DOM,你可以按索引顺序获取它们:
(Prototype示例)
myNodes = document.body.descendants()
alert(document.body.descendants()[1].innerHTML)
您可以遍历所有节点并为它们提供一个唯一的className,稍后您可以轻松选择它。
答案 6 :(得分:2)
您可以将id属性设置为计算值。原型库中有一个函数可以为您完成此任务。
http://www.prototypejs.org/api/element/identify
我最喜欢的javascript库是jQuery。不幸的是,jQuery没有像identify那样的功能。但是,您仍然可以将id属性设置为您自己生成的值。
http://docs.jquery.com/Attributes/attr#keyfn
以下是jQuery文档的部分片段,它根据页面中的位置为div设置id:
$(document).ready(function(){
$("div").attr("id", function (arr) {
return "div-id" + arr;
});
});
答案 7 :(得分:1)
您还可以使用pguid(页面唯一标识符)生成唯一标识符:
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"
答案 8 :(得分:1)
使用元素的鼠标和/或位置属性生成唯一ID。
答案 9 :(得分:1)
您可以使用以下函数为DOM中的任何给定节点生成稳定的唯一标识符:
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('/');
}
这将为类似这样的结构创建doc/0
,doc/0/0
,doc/0/1
,doc/0/1/0
,doc/0/1/1
等标识符:
<div>
<div />
<div>
<div />
<div />
</div>
</div>
您还可以进行一些优化和更改,例如:
在while
循环中break
当node
具有您知道唯一的属性时@id
,例如reverse()
pieces
不是piece
,目前看起来更像是从
如果您不需要文档节点的标识符,则不包括第一个doc
annotate
以某种方式将标识符保存在节点上,并将该值重用于子节点,以避免再次遍历树。
如果您正在将这些标识符写回XML,请使用另一个连接字符,如果您正在编写的属性受到限制。
答案 10 :(得分:0)
在javascript中,您可以将自定义ID字段附加到节点
if(node.id) {
node.myId = node.id;
} else {
node.myId = createId();
}
// store myId
这是一个黑客攻击,但它会给每个节点一个你可以使用的id。当然,document.getElementById()
不会关注它。
答案 11 :(得分:0)
我想'我刚刚解决了类似的问题。但是,我在浏览器DOM环境中使用jQuery。
var objA = $(“某些dom元素的选择器”); var objB = $(“选择一些其他dom元素”);
if(objA [0] === objB [0]){ //大!这两个对象指向完全相同的dom节点 }
答案 12 :(得分:0)
好的,没有自动与DOM元素关联的ID。 DOM具有元素的层次结构,这是主要信息。 从这个角度来看,您可以使用jQuery或jQLite将数据与DOM元素相关联。当您必须将自定义数据绑定到元素时,它可以解决一些问题。