Получить уникальный селектор элемента в Jquery - PullRequest
50 голосов
/ 18 апреля 2011

Я хочу создать что-то вроде рекордера, который отслеживает все действия пользователя.Для этого мне нужно идентифицировать элементы, с которыми взаимодействует пользователь, чтобы я мог ссылаться на эти элементы в более поздней сессии.

Говоря в псевдокоде, я хочу иметь возможность сделать что-то вроде следующего1003 *

Пример HTML (может быть любой сложности):

<html>
<body>
  <div class="example">
    <p>foo</p>
    <span><a href="bar">bar</a></span>
  </div>
</body>
</html>

Пользователь нажимает на что-то, например на ссылку.Теперь мне нужно идентифицировать выбранный элемент и сохранить его местоположение в дереве DOM для дальнейшего использования:

(any element).onclick(function() {
  uniqueSelector = $(this).getUniqueSelector();
})

Теперь uniqueSelector должен выглядеть примерно так (я не против, если это стиль селектора xpath или css):

html > body > div.example > span > a

Это дало бы возможность сохранить эту строку селектора и использовать ее позднее для воспроизведения действий, выполненных пользователем.

Как это возможно?

Обновление

Получил мой ответ: Получение селектора jQuery для элемента

Ответы [ 12 ]

36 голосов
/ 18 апреля 2011

Я отвечу на это сам, потому что я нашел решение, которое мне пришлось изменить.Следующий скрипт работает и основан на скрипте Blixt :

jQuery.fn.extend({
    getPath: function () {
        var path, node = this;
        while (node.length) {
            var realNode = node[0], name = realNode.localName;
            if (!name) break;
            name = name.toLowerCase();

            var parent = node.parent();

            var sameTagSiblings = parent.children(name);
            if (sameTagSiblings.length > 1) { 
                var allSiblings = parent.children();
                var index = allSiblings.index(realNode) + 1;
                if (index > 1) {
                    name += ':nth-child(' + index + ')';
                }
            }

            path = name + (path ? '>' + path : '');
            node = parent;
        }

        return path;
    }
});
16 голосов
/ 05 ноября 2014

То же решение, что и у @Alp, но совместимое с несколькими элементами jQuery.

jQuery('.some-selector') может привести к одному или нескольким элементам DOM.Решение @ Alp работает, к сожалению, только с первым.Мое решение объединяет все их с ,.

Если вы хотите просто обработать первый элемент, сделайте это так:

jQuery('.some-selector').first().getPath();

// or
jQuery('.some-selector:first').getPath();

Улучшенная версия

jQuery.fn.extend({
    getPath: function() {
        var pathes = [];

        this.each(function(index, element) {
            var path, $node = jQuery(element);

            while ($node.length) {
                var realNode = $node.get(0), name = realNode.localName;
                if (!name) { break; }

                name = name.toLowerCase();
                var parent = $node.parent();
                var sameTagSiblings = parent.children(name);

                if (sameTagSiblings.length > 1)
                {
                    var allSiblings = parent.children();
                    var index = allSiblings.index(realNode) + 1;
                    if (index > 0) {
                        name += ':nth-child(' + index + ')';
                    }
                }

                path = name + (path ? ' > ' + path : '');
                $node = parent;
            }

            pathes.push(path);
        });

        return pathes.join(',');
    }
});
5 голосов
/ 18 апреля 2011
(any element).onclick(function() {
  uniqueSelector = $(this).getUniqueSelector();
})

this IS уникальный селектор и путь к этому нажатому элементу. Почему бы не использовать это? Вы можете использовать метод jquery $.data(), чтобы установить селектор jquery. Или просто нажмите на элементы, которые вам понадобятся в будущем:

var elements = [];
(any element).onclick(function() {
  elements.push(this);
})

Если вам действительно нужен xpath, вы можете рассчитать его, используя следующий код:

  function getXPath(node, path) {
    path = path || [];
    if(node.parentNode) {
      path = getXPath(node.parentNode, path);
    }

    if(node.previousSibling) {
      var count = 1;
      var sibling = node.previousSibling
      do {
        if(sibling.nodeType == 1 && sibling.nodeName == node.nodeName) {count++;}
        sibling = sibling.previousSibling;
      } while(sibling);
      if(count == 1) {count = null;}
    } else if(node.nextSibling) {
      var sibling = node.nextSibling;
      do {
        if(sibling.nodeType == 1 && sibling.nodeName == node.nodeName) {
          var count = 1;
          sibling = null;
        } else {
          var count = null;
          sibling = sibling.previousSibling;
        }
      } while(sibling);
    }

    if(node.nodeType == 1) {
      path.push(node.nodeName.toLowerCase() + (node.id ? "[@id='"+node.id+"']" : count > 0 ? "["+count+"]" : ''));
    }
    return path;
  };

Ссылка: http://snippets.dzone.com/posts/show/4349

4 голосов
/ 18 апреля 2011

Я думаю, что лучшим решением было бы создать случайный идентификатор и затем получить доступ к элементу на основе этого идентификатора:

Назначение уникального идентификатора:

// or some other id-generating algorithm
$(this).attr('id', new Date().getTime()); 

Выбор на основе уникального идентификатора:

// getting unique id
var uniqueId = $(this).getUniqueId();

// or you could just get the id:
var uniqueId = $(this).attr('id');

// selecting by id:
var element = $('#' + uniqueId);

// if you decide to use another attribute other than id:
var element = $('[data-unique-id="' + uniqueId + '"]');
3 голосов
/ 21 октября 2018

Чистое решение JavaScript

Примечание: Используется Array.from и Array.prototype.filter , оба из которых должныполи заполнены в IE11.

function getUniqueSelector(node) {
  let selector = "";
  while (node.parentElement) {
    const siblings = Array.from(node.parentElement.children).filter(
      e => e.tagName === node.tagName
    );
    selector =
      (siblings.indexOf(node)
        ? `${node.tagName}:nth-of-type(${siblings.indexOf(node) + 1})`
        : `${node.tagName}`) + `${selector ? " > " : ""}${selector}`;
    node = node.parentElement;
  }
  return `html > ${selector.toLowerCase()}`;
}

Использование

getUniqueSelector(document.getElementsByClassName('SectionFour')[0]);

getUniqueSelector(document.getElementById('content'));
3 голосов
/ 06 сентября 2018

Хотя вопрос был для jQuery, в ES6 довольно легко получить что-то похожее на @ Alp's для Vanilla JavaScript (я также добавил пару строк, отслеживающих nameCount, чтобы минимизировать использование nth-child ):

function getSelectorForElement (elem) {
    let path;
    while (elem) {
        let subSelector = elem.localName;
        if (!subSelector) {
            break;
        }
        subSelector = subSelector.toLowerCase();

        const parent = elem.parentElement;

        if (parent) {
            const sameTagSiblings = parent.children;
            if (sameTagSiblings.length > 1) {
                let nameCount = 0;
                const index = [...sameTagSiblings].findIndex((child) => {
                    if (elem.localName === child.localName) {
                        nameCount++;
                    }
                    return child === elem;
                }) + 1;
                if (index > 1 && nameCount > 1) {
                    subSelector += ':nth-child(' + index + ')';
                }
            }
        }

        path = subSelector + (path ? '>' + path : '');
        elem = parent;
    }
    return path;
}
2 голосов
/ 08 мая 2017

Если у вас есть атрибут идентичности (например, id = "что-то"), вы должны получить его значение, например,

var selector = "[id='" + $(yourObject).attr("id") + "']";
console.log(selector); //=> [id='something']
console.log($(selector).length); //=> 1

Если у вас нет атрибута идентификации и вы хотите получить его селектор, вы можете создать атрибут идентификации. Нечто подобное выше,

var uuid = guid();
$(yourObject).attr("id", uuid); // Set the uuid as id of your object.

Вы можете использовать свой собственный метод guid или исходный код, найденный в this , так что ответьте

function guid() {
    function s4() {
        return Math.floor((1 + Math.random()) * 0x10000)
                .toString(16)
                .substring(1);
    }
    return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
            s4() + '-' + s4() + s4() + s4();
}
2 голосов
/ 20 февраля 2014

Этот ответ не удовлетворяет первоначальному описанию вопроса, однако он отвечает на заглавный вопрос.Я пришел к этому вопросу в поисках способа получить уникальный селектор для элемента, но у меня не было необходимости в том, чтобы селектор был действительным между загрузками страниц.Итак, мой ответ не будет работать между загрузками страниц.

Мне кажется, что модификация DOM не идеальна, но это хороший способ создать селектор, который уникален без множества кода.Я получил эту идею после прочтения ответа @ Eli:

Назначьте пользовательский атрибут с уникальным значением.

$(element).attr('secondary_id', new Date().getTime())
var secondary_id = $(element).attr('secondary_id');

Затем используйте этот уникальный идентификатор для создания селектора CSS.

var selector = '[secondary_id='+secondary_id+']';

Тогда у вас есть селектор, который выберет ваш элемент.

var found_again = $(selector);

И многие хотят проверить, чтобы убедиться, что в элементе уже нет атрибута secondary_id.

if ($(element).attr('secondary_id')) {
  $(element).attr('secondary_id', (new Date()).getTime());
}
var secondary_id = $(element).attr('secondary_id');

Собираем все вместе

$.fn.getSelector = function(){
  var e = $(this);

  // the `id` attribute *should* be unique.
  if (e.attr('id')) { return '#'+e.attr('id') }

  if (e.attr('secondary_id')) {
    return '[secondary_id='+e.attr('secondary_id')+']'
  }

  $(element).attr('secondary_id', (new Date()).getTime());

  return '[secondary_id='+e.attr('secondary_id')+']'
};

var selector = $('*').first().getSelector();
1 голос
/ 07 февраля 2018

Вы также можете взглянуть на findCssSelector .Код в моем другом ответе .

0 голосов
/ 18 апреля 2011
$(document).ready(function() {
    $("*").click(function(e) {
        var path = [];
        $.each($(this).parents(), function(index, value) {
            var id = $(value).attr("id");
            var class = $(value).attr("class");
            var element = $(value).get(0).tagName
                path.push(element + (id.length > 0 ? " #" + id : (class.length > 0 ? " .": "") + class));
        });
        console.log(path.reverse().join(">"));
        return false;
    });
});

Рабочий пример: http://jsfiddle.net/peeter/YRmr5/

Вы, вероятно, столкнетесь с проблемами при использовании селектора * (очень медленного) и остановке всплывающего события, но на самом деле не сможете помочь без дополнительного HTMLкод.

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