Как создать уникальный селектор CSS для элемента DOM? - PullRequest
9 голосов
/ 21 декабря 2011

Мне нужно сгенерировать уникальный селектор CSS для элементов.
В частности, у меня есть обработчик события onclick, который должен помнить, какой целевой элемент был нажат и отправлять эту информацию на мой сервер.Есть ли способ сделать это без внесения изменений в DOM?

PS Мой код javascript должен выполняться на различных
сторонних веб-сайтах, поэтому я не могу делать никаких предположений относительно html.

Ответы [ 6 ]

4 голосов
/ 21 декабря 2011

Да, вы могли бы сделать это.Но с несколькими оговорками.Чтобы гарантировать, что селекторы уникальны, вам нужно использовать :nth-child(), который не поддерживается повсеместно.Если вы захотите поместить эти селекторы CSS в файлы CSS, это не сработает во всех браузерах.

Я бы сделал это примерно так:

function () {
    if (this.id) {
        return sendToServer('#' + this.id);
    }
    var parent = this.parentNode;
    var selector = '>' + this.nodeName + ':nth-child(' + getChildNumber(this) ')';
    while (!parent.id && parent.nodeName.toLowerCase() !== 'body') {
        selector = '>' + this.nodeName + ':nth-child(' + getChildNumber(parent) + ')' + selector;
        parent = parent.parentNode;
    }
    if (parent.nodeName === 'body') {
        selector = 'body' + selector;
    } else {
        selector = '#' + parent.id + selector;
    }
    return sendToServer(selector);
}

Тогдадобавьте это в ваш обработчик кликов для каждого элемента, который вы хотите смоделировать.Я оставлю вас для реализации getChildNumber().

Редактировать: Только что видел ваш комментарий о том, что это сторонний код ... так что вы можете добавить аргумент event, заменить всеэкземпляры this с event.target, а затем просто присоедините функцию к событию click window, если это проще.

3 голосов
/ 05 апреля 2018

Эта функция создает длинный, но довольно практичный уникальный селектор, работает быстро.

const getCssSelector = (el) => {
  let path = [], parent;
  while (parent = el.parentNode) {
    path.unshift(`${el.tagName}:nth-child(${[].indexOf.call(parent.children, el)+1})`);
    el = parent;
  }
  return `${path.join(' > ')}`.toLowerCase();
};

Пример результата:

html:nth-child(1) > body:nth-child(2) > div:nth-child(1) > div:nth-child(1) > main:nth-child(3) > div:nth-child(2) > p:nth-child(2)

Следующий код создает немного более красивый и короткий селектор

const getCssSelectorShort = (el) => {
  let path = [], parent;
  while (parent = el.parentNode) {
    let tag = el.tagName, siblings;
    path.unshift(
      el.id ? `#${el.id}` : (
        siblings = parent.children,
        [].filter.call(siblings, sibling => sibling.tagName === tag).length === 1 ? tag :
        `${tag}:nth-child(${1+[].indexOf.call(siblings, el)})`
      )
    );
    el = parent;
  };
  return `${path.join(' > ')}`.toLowerCase();
};

Пример результата:

html > body > div > div > main > div:nth-child(2) > p:nth-child(2)
1 голос
/ 21 февраля 2018

Проверьте эту библиотеку генератора селекторов CSS @ medv / finder

Build Status

  • Генерирует кратчайшие селекторы
  • Уникальные селекторы на странице
  • Стабильные и надежные селекторы
  • 2,9 кБ, gzip и уменьшенный размер

Пример сгенерированного селектора:

.blog > article:nth-child(3) .add-comment
1 голос
/ 11 сентября 2014
"use strict";
function getSelector(_context){
     var index, localName,pathSelector, that = _context, node;
     if(that =='null') throw 'not an  dom reference';
     index =  getIndex(that);

     while(that.tagName){
       pathSelector = that.localName+(pathSelector?'>'+pathSelector :'');
       that = that.parentNode;
     }
    pathSelector = pathSelector+':nth-of-type('+index+')';

    return pathSelector;
}

function getIndex(node){
    var i=1;
    var tagName = node.tagName;

    while(node.previousSibling){
    node = node.previousSibling;
        if(node.nodeType === 1 && (tagName.toLowerCase() == node.tagName.toLowerCase())){
            i++;
        }
    }
    return i;
}
document.addEventListener('DOMContentLoaded', function(){
   document.body.addEventListener('mouseover', function(e){
     var c = getSelector(e.target);
         var  element = document.querySelector(c);
          //console.log(element);
      console.log(c);
        //element.style.color = "red"

   });
});

Вы можете попробовать это.без использования jquery.

1 голос
/ 21 декабря 2011

допустим, у вас есть список ссылок для простоты: вы можете просто передать индекс триггерного элемента в коллекцию всех элементов

<a href="#">...</a>
<a href="#">...</a>    
<a href="#">...</a>

js (jQuery 1.7+, Iused .on() в противном случае использовать bind()) функция может быть

var triggers = $('a');
triggers.on('click', function(e) {
   e.preventDefault();
   var index = triggers.index($(this));
   /* ajax call passing index value */
});

, так что если вы щелкнете по третьему элементу, переданное значение индекса будет равно 2. (индекс на основе 0);конечно, это верно, пока код (DOM) не изменяется.Позже вы можете использовать этот индекс для создания правила CSS для этого элемента, например, используя :nth-child

В противном случае, если каждый из ваших элементов имеет свой атрибут (например, идентификатор), вы можете передать этот атрибут

пример для JsFiddle: http://jsfiddle.net/t7J8T/

1 голос
/ 21 декабря 2011

Возможно, вы могли бы пройтись по дереву DOM от узла обратно к элементу body, чтобы сгенерировать селектор.

Firebug имеет функцию для этого, используя как XPath, так и CSS-селекторы.

См. этот ответ

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...