Подтвердить что ты не робот

Уникальный идентификатор элемента, даже если элемент не имеет одного

Я пишу GreaseMonkey script, где я повторяюсь через кучу элементов. Для каждого элемента мне нужен идентификатор строки, который я могу использовать для ссылки на этот элемент позже. Сам элемент не имеет атрибута id, и я не могу изменить исходный документ, чтобы дать ему один (хотя я могу внести изменения DOM в свой script). Я не могу сохранить ссылки в моем script, потому что, когда они мне понадобятся, сам GreaseMonkey script выйдет за рамки. Есть ли способ получить "внутренний" идентификатор, который использует браузер, например? Решение только для Firefox прекрасно; кросс-браузерное решение, которое может быть применено в других сценариях, было бы удивительным.

Edit:

  • Если GreaseMonkey script выходит за пределы области действия, как вы ссылаетесь на элементы позже? Они GreaseMonkey script добавляют события к объектам DOM. Я не могу хранить ссылки в массиве или какой-либо другой подобный механизм, потому что когда событие срабатывает, массив исчезнет, ​​потому что GreaseMonkey script выйдет за рамки. Таким образом, событие должно каким-то образом узнать о ссылке на элемент, которую имел script, когда событие было присоединено. И элемент, о котором идет речь, не тот, к которому он прикреплен.

  • Не можете ли вы просто использовать настраиваемое свойство для элемента? Да, но проблема в поиске. Мне пришлось бы прибегать к повторению всех элементов, которые ищут тот, у которого это настраиваемое свойство установлено на желаемый идентификатор. Это будет работать, конечно, но в больших документах это может занять много времени. Я ищу что-то, где браузер может выполнять работу поиска.

  • Подождите, можете ли вы или не можете изменить документ? Я не могу изменить исходный документ, но я могу внести изменения DOM в script. Я уточню в вопросе.

  • Можете ли вы не использовать закрытие? Затворы оказались полезными, хотя первоначально я думал, что они не будут. См. Мой более поздний пост.

Звучит как ответ на вопрос: "Есть ли какой-то внутренний идентификатор браузера, который я мог бы использовать?" "Нет".

4b9b3361

Ответ 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, используйте другой символ конкатенации, если атрибут, который вы пишете, ограничен.