获取元素的jQuery选择器

时间:2010-01-14 23:18:32

标签: javascript jquery jquery-selectors

在伪代码中,这就是我想要的。

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节点对象创建对象,则它不起作用。

9 个答案:

答案 0 :(得分:51)

我现在看到一个插件存在(我也想到了同名),但这里只是我编写的一些快速JavaScript。它不需要考虑元素的id或类 - 只有结构(并且在节点名称不明确时添加: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;
};

答案 1 :(得分:8)

jQuery-GetPath是一个很好的起点:它会给你这个项目的祖先,就像这样:

var path = $('#foo').getPath();
// e.g., "html > body > div#bar > ul#abc.def.ghi > li#foo"

答案 2 :(得分:7)

这是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;
};

答案 3 :(得分:5)

我只是想分享我的版本,因为它很清楚。我在所有常见的浏览器中测试了这个脚本,它就像老板一样工作。

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;
}

答案 4 :(得分:3)

与@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(',');
    }
});

答案 5 :(得分:2)

如果您正在寻找全面的非jQuery解决方案,那么您应该尝试axe.utils.getSelector

答案 6 :(得分:1)

跟进亚历克斯所写的内容。 jQuery-GetPath是一个很好的起点,但我对其进行了一些修改,以便合并:eq(),允许我区分多个无id元素。

在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&gt; body&gt; ul#hello&gt; li.5:eq(1)”

的路径

答案 7 :(得分:0)

您还可以查看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;

};

答案 8 :(得分:-1)

$.fn.getSelector = function(){
    var $ele = $(this);
    return '#' + $ele.parents('[id!=""]').first().attr('id') 
               + ' .' + $ele.attr('class');
};