Уникальный идентификатор элемента, даже если элемент не имеет одного
Я пишу GreaseMonkey script, где я повторяюсь через кучу элементов. Для каждого элемента мне нужен идентификатор строки, который я могу использовать для ссылки на этот элемент позже. Сам элемент не имеет атрибута id
, и я не могу изменить исходный документ, чтобы дать ему один (хотя я могу внести изменения DOM в свой script). Я не могу сохранить ссылки в моем script, потому что, когда они мне понадобятся, сам GreaseMonkey script выйдет за рамки. Есть ли способ получить "внутренний" идентификатор, который использует браузер, например? Решение только для Firefox прекрасно; кросс-браузерное решение, которое может быть применено в других сценариях, было бы удивительным.
Edit:
-
Если GreaseMonkey script выходит за пределы области действия, как вы ссылаетесь на элементы позже? Они GreaseMonkey script добавляют события к объектам DOM. Я не могу хранить ссылки в массиве или какой-либо другой подобный механизм, потому что когда событие срабатывает, массив исчезнет, потому что GreaseMonkey script выйдет за рамки. Таким образом, событие должно каким-то образом узнать о ссылке на элемент, которую имел script, когда событие было присоединено. И элемент, о котором идет речь, не тот, к которому он прикреплен.
-
Не можете ли вы просто использовать настраиваемое свойство для элемента? Да, но проблема в поиске. Мне пришлось бы прибегать к повторению всех элементов, которые ищут тот, у которого это настраиваемое свойство установлено на желаемый идентификатор. Это будет работать, конечно, но в больших документах это может занять много времени. Я ищу что-то, где браузер может выполнять работу поиска.
-
Подождите, можете ли вы или не можете изменить документ? Я не могу изменить исходный документ, но я могу внести изменения DOM в script. Я уточню в вопросе.
-
Можете ли вы не использовать закрытие? Затворы оказались полезными, хотя первоначально я думал, что они не будут. См. Мой более поздний пост.
Звучит как ответ на вопрос: "Есть ли какой-то внутренний идентификатор браузера, который я мог бы использовать?" "Нет".
Ответы
Ответ 1
ОБНОВЛЕНИЕ: Закрытие - это действительно ответ. Поэтому, после того, как я поработал с ним, я понял, почему закрытие было изначально проблематичным и как его исправить. Трудная вещь с закрытием - вы должны быть осторожны, когда итерации через элементы не заканчиваются всеми вашими замыканиями, ссылающимися на один и тот же элемент. Например, это не работает:
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) Нет, нет внутренних идентификаторов, которые вы можете использовать; 2) для этого вам следует использовать замыкания. Поэтому я просто поддержал первых людей, чтобы сказать, были ли внутренние идентификаторы или кто рекомендовал создавать идентификаторы, а также всех, кто упомянул о закрытии. Спасибо за помощь!
Ответ 2
Немного смущенный формулировкой вашего вопроса - вы говорите, что вам "нужен идентификатор строки, который [вы] можете использовать для ссылки на этот элемент позже", но что вы "не можете хранить ссылки в [вашем] script, потому что, когда они вам понадобятся, GreaseMonkey script сам выйдет за рамки."
Если script выйдет из области видимости, то как вы ссылаетесь на них позже?!
Я проигнорирую тот факт, что меня смущает то, что вы получаете, и говорите вам, что я часто пишу сценарии 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 script.
ОБНОВЛЕНИЕ: Закрытие - это путь - лично, как ядро-разработчик 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 или что-то еще).
Возможно, если вы опубликуете пример того, что вы пытаетесь сделать, было бы проще помочь вам, если это не так.
Ответ 3
Закрытие - это путь. Таким образом, вы будете иметь точную ссылку на элемент, который даже выживет при перетасовке DOM.
Пример для тех, кто не знает замыкания:
var saved_element = findThatDOMNode();
document.body.onclick = function()
{
alert(saved_element); // it still there!
}
Если вам нужно было сохранить его в куки файле, я рекомендую вам вычислить XPath (например, подходите к DOM, подсчитывая предыдущих братьев и сестер, пока не найдете элемент с идентификатором, и вы получите что-то вроде [@id=foo]/div[4]/p[2]/a
).
XPointer является решением W3C для этой проблемы.
Ответ 4
Ответ: нет, нет внутреннего идентификатора, к которому вы можете получить доступ. Opera и IE (возможно, Safari?) Поддерживают .sourceIndex
(который изменяется, если DOM делает), но Firefox ничего подобного не имеет.
Вы можете смоделировать исходный индекс, создав Xpath для данного node или найдя индекс node из document.getElementsByTagName('*')
, который всегда будет возвращать элементы в порядке источника.
Все это требует, конечно, полностью статического файла. Изменения в DOM нарушат поиск.
Я не понимаю, как вы можете потерять ссылки на узлы, но не на (теоретические) внутренние идентификаторы? Либо закрываются и присваиваются, либо нет. Или я что-то упускаю?
Ответ 5
Если вы можете написать в DOM (я уверен, что вы можете). Я бы решил это следующим образом:
Функция возвращает или генерирует идентификатор:
//(function () {
var idCounter = new Date().getTime();
function getId( node ) {
return (node.id) ? node.id : (node.id = 'tempIdPrefix_' + idCounter++ );
}
//})();
Используйте это, чтобы получить идентификатор по мере необходимости:
var n = document.getElementById('someid');
getId(n); // returns "someid"
var n = document.getElementsByTagName('div')[1];
getId(n); // returns "tempIdPrefix_1224697942198"
Таким образом, вам не нужно беспокоиться о том, как выглядит HTML, когда сервер передает его вам.
Ответ 6
Вы можете установить атрибут id для вычисленного значения. В библиотеке прототипов есть функция, которая может сделать это для вас.
http://www.prototypejs.org/api/element/identify
Моя любимая библиотека javascript - jQuery. К сожалению, jQuery не имеет такой функции, как идентификация. Однако вы все равно можете установить атрибут id на значение, которое вы генерируете самостоятельно.
http://docs.jquery.com/Attributes/attr#keyfn
Вот частичный фрагмент из jQuery docs, который устанавливает id для divs в зависимости от позиции на странице:
$(document).ready(function(){
$("div").attr("id", function (arr) {
return "div-id" + arr;
});
});
Ответ 7
Если вы не изменяете DOM, вы можете получить их все по индексированному порядку:
(Prototype пример)
myNodes = document.body.descendants()
alert(document.body.descendants()[1].innerHTML)
Вы можете пропустить все узлы и дать им уникальное имя класса, которое вы могли бы впоследствии легко выбрать.
Ответ 8
Вы также можете использовать 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"
http://appengine.bravo9.com/b9j/documentation/pguid.html
Ответ 9
Используйте мышь и/или позиционные свойства элемента для создания уникального идентификатора.
Ответ 10
В javascript вы можете прикрепить пользовательское поле идентификатора к node
if(node.id) {
node.myId = node.id;
} else {
node.myId = createId();
}
// store myId
Немного взломать, но он даст каждому node идентификатор, который вы можете использовать. Конечно, document.getElementById()
не обратит на это внимания.
Ответ 11
Я думаю: "Я только что решил проблему, подобную этой. Тем не менее, я использую jQuery в среде DOM браузера.
var objA = $( "селектор для некоторого элемента dom" );
var objB = $( "селектор к некоторому другому элементу dom" );
if (objA [0] === objB [0]) { // ВЕЛИКИЙ! два объекта указывают на то же самое dom node
}
Ответ 12
ОК, нет идентификатора, связанного с элементом DOM автоматически.
DOM имеет иерархическую структуру элементов, которая является основной информацией.
С этой точки зрения вы можете связать данные с элементами DOM с помощью jQuery или jQLite. Он может решить некоторые проблемы, когда вам нужно привязать пользовательские данные к элементам.
Ответ 13
Вы можете создать стабильный уникальный идентификатор для любого заданного node в 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
, в настоящее время он просто больше похож на структуру DOM, которую ID генерирует из
-
Не включать первый piece
doc
, если вам не нужен идентификатор документа node
-
Сохраните идентификатор в node каким-либо образом и повторно используйте это значение для дочерних узлов, чтобы избежать повторного перемещения по всему дереву.
-
Если вы пишете эти идентификаторы обратно в XML, используйте другой символ конкатенации, если атрибут, который вы пишете, ограничен.