Получение селектора jQuery для элемента - PullRequest
43 голосов
/ 15 января 2010

В коде psuedo это то, что я хочу.

var selector = $(this).cssSelectorAsString(); // Made up method...
// selector is now something like: "html>body>ul>li>img[3]"
var element = $(selector);

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

Я заметил, что в jquery есть метод selector, но он не работает в этом контексте. Это работает, только если объект был создан с помощью селектора. Он не работает, если объект был создан с объектом узла HTML.

Ответы [ 10 ]

52 голосов
/ 15 января 2010

Теперь я вижу, что существовал плагин (с тем же именем, о котором я тоже думал), но вот лишь небольшой быстрый JavaScript, который я написал. Он не учитывает идентификаторы или классы элементов & ndash; только структура (и добавляет :eq(x), где имя узла неоднозначно).

jQuery.fn.getPath = function () {
    if (this.length != 1) throw 'Requires one element.';

    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 siblings = parent.children(name);
        if (siblings.length > 1) { 
            name += ':eq(' + siblings.index(realNode) + ')';
        }

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

    return path;
};
17 голосов
/ 26 августа 2015

TL; DR - это более сложная проблема, чем кажется, и вам следует использовать библиотеку .


Эта проблема кажется простой на первый взгляд, но сложнее, чем кажется, так же как замена простых URL-адресов ссылками нетривиальна . Некоторые соображения:

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

8 голосов
/ 15 января 2010

jQuery-GetPath - хорошая отправная точка: она даст вам предков предмета, например:

var path = $('#foo').getPath();
// e.g., "html > body > div#bar > ul#abc.def.ghi > li#foo"
7 голосов
/ 27 июля 2011

Вот версия ответа Blixt, которая работает в IE:

jQuery.fn.getPath = function () {
    if (this.length != 1) throw 'Requires one element.';

    var path, node = this;
    while (node.length) {
        var realNode = node[0];
        var name = (

            // IE9 and non-IE
            realNode.localName ||

            // IE <= 8
            realNode.tagName ||
            realNode.nodeName

        );

        // on IE8, nodeName is '#document' at the top level, but we don't need that
        if (!name || name == '#document') break;

        name = name.toLowerCase();
        if (realNode.id) {
            // As soon as an id is found, there's no need to specify more.
            return name + '#' + realNode.id + (path ? '>' + path : '');
        } else if (realNode.className) {
            name += '.' + realNode.className.split(/\s+/).join('.');
        }

        var parent = node.parent(), siblings = parent.children(name);
        if (siblings.length > 1) name += ':eq(' + siblings.index(node) + ')';
        path = name + (path ? '>' + path : '');

        node = parent;
    }

    return path;
};
5 голосов
/ 01 июня 2013

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

jQuery.fn.getPath = function () {
    var current = $(this);
    var path = new Array();
    var realpath = "BODY";
    while ($(current).prop("tagName") != "BODY") {
        var index = $(current).parent().find($(current).prop("tagName")).index($(current));
        var name = $(current).prop("tagName");
        var selector = " " + name + ":eq(" + index + ") ";
        path.push(selector);
        current = $(current).parent();
    }
    while (path.length != 0) {
        realpath += path.pop();
    }
    return realpath;
}
3 голосов
/ 05 ноября 2014

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

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

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

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)
                {
                    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(',');
    }
});
2 голосов
/ 18 сентября 2017

Если вы ищете комплексное решение, отличное от jQuery, попробуйте axe.utils.getSelector .

1 голос
/ 17 ноября 2014

В продолжение того, что написал Алекс. jQuery-GetPath - отличная отправная точка, но я немного изменил ее, добавив: eq (), что позволяет мне различать несколько элементов без идентификатора.

Добавьте это перед строкой возврата getPath:

if (typeof id == 'undefined' && cur != 'body') {
    allSiblings = $(this).parent().children(cur);
    var index = allSiblings.index(this);// + 1;
    //if (index > 0) {
        cur += ':eq(' + index + ')';
    //}
}

Это вернет путь, подобный "html> body> ul # hello> li.5: eq (1)"

0 голосов
/ 07 февраля 2018

Вы также можете взглянуть на findCssSelector , который используется в инструментах разработчика Firefox для сохранения выбранного в данный момент узла при обновлении страницы. Он не использует jQuery или какую-либо библиотеку.

const findCssSelector = function(ele) {
ele = getRootBindingParent(ele);
  let document = ele.ownerDocument;
  if (!document || !document.contains(ele)) {
    throw new Error("findCssSelector received element not inside document");
  }

  let cssEscape = ele.ownerGlobal.CSS.escape;

  // document.querySelectorAll("#id") returns multiple if elements share an ID
  if (ele.id &&
      document.querySelectorAll("#" + cssEscape(ele.id)).length === 1) {
    return "#" + cssEscape(ele.id);
  }

  // Inherently unique by tag name
  let tagName = ele.localName;
  if (tagName === "html") {
    return "html";
  }
  if (tagName === "head") {
    return "head";
  }
  if (tagName === "body") {
    return "body";
  }

  // We might be able to find a unique class name
  let selector, index, matches;
  if (ele.classList.length > 0) {
    for (let i = 0; i < ele.classList.length; i++) {
      // Is this className unique by itself?
      selector = "." + cssEscape(ele.classList.item(i));
      matches = document.querySelectorAll(selector);
      if (matches.length === 1) {
        return selector;
      }
      // Maybe it's unique with a tag name?
      selector = cssEscape(tagName) + selector;
      matches = document.querySelectorAll(selector);
      if (matches.length === 1) {
        return selector;
      }
      // Maybe it's unique using a tag name and nth-child
      index = positionInNodeList(ele, ele.parentNode.children) + 1;
      selector = selector + ":nth-child(" + index + ")";
      matches = document.querySelectorAll(selector);
      if (matches.length === 1) {
        return selector;
      }
    }
  }

  // Not unique enough yet.  As long as it's not a child of the document,
  // continue recursing up until it is unique enough.
  if (ele.parentNode !== document) {
    index = positionInNodeList(ele, ele.parentNode.children) + 1;
    selector = findCssSelector(ele.parentNode) + " > " +
      cssEscape(tagName) + ":nth-child(" + index + ")";
  }

  return selector;

};
0 голосов
/ 10 апреля 2015
$.fn.getSelector = function(){
    var $ele = $(this);
    return '#' + $ele.parents('[id!=""]').first().attr('id') 
               + ' .' + $ele.attr('class');
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...