Javascript 获取元素的 jQuery 选择器
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2068272/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Getting a jQuery selector for an element
提问by Alex Wayne
In psuedo code, this is what I want.
在伪代码中,这就是我想要的。
var selector = $(this).cssSelectorAsString(); // Made up method...
// selector is now something like: "html>body>ul>li>img[3]"
var element = $(selector);
The reason is that I need to pass this off to an external environment, where a string is my only way to exchange data. This external environment then needs to send back a result, along with what element to update. So I need to be able to serialize a unique CSS selector for every element on the page.
原因是我需要将其传递给外部环境,其中字符串是我交换数据的唯一方式。然后这个外部环境需要发回一个结果,以及要更新的元素。所以我需要能够为页面上的每个元素序列化一个唯一的 CSS 选择器。
I noticed jquery has a selectormethod, but it does not appear to work in this context. It only works if the object was created with a selector. It does not work if the object was created with an HTML node object.
我注意到 jquery 有一个selector方法,但它似乎在这种情况下不起作用。仅当对象是使用选择器创建时才有效。如果对象是使用 HTML 节点对象创建的,则它不起作用。
回答by Blixt
I see now that a plugin existed (with the same name I thought of too), but here's just some quick JavaScript I wrote. It takes no consideration to the ids or classes of elements – only the structure (and adds :eq(x)where a node name is ambiguous).
我现在看到存在一个插件(我也想到了同名),但这里只是我写的一些快速 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;
};
回答by Dan Dascalescu
TL;DR - this is a more complex problem than it seems and you should use a library.
TL;DR - 这是一个比看起来更复杂的问题,您应该使用library。
This problem appears easy at the first glance, but it's trickier than it seems, just as replacing plain URLs with links is non-trivial. Some considerations:
这个问题乍一看似乎很容易,但它比看起来更棘手,就像用链接替换普通 URL 并非易事一样。一些考虑:
- Using descendant selectors vs. child selectors can lead to cases where the selector isn't unique.
- Using
:eq()limits the usefulness of the solution, as it will requirejQuery - Using tag+nth-child selectors can result in unnecessarily long selectors
- Not taking advantage of ids makes the selector less robust to changes in the page structure.
- 使用后代选择器与子选择器会导致选择器不唯一的情况。
- 使用
:eq()限制了解决方案的实用性,因为它将需要jQuery - 使用 tag+nth-child 选择器会导致不必要的长选择器
- 不利用 ids 会使选择器对页面结构变化的鲁棒性降低。
Further proof that the problem isn't as easy as it seems: there are 10+ libraries that generate CSS selectors, and the author of one of them has published this comparison.
进一步证明问题并不像看起来那么简单:有 10 多个库可以生成 CSS 选择器,其中之一的作者发表了这个比较。
回答by Agos
jQuery-GetPathis a good starting point: it'll give you the item's ancestors, like this:
jQuery-GetPath是一个很好的起点:它将为您提供项目的祖先,如下所示:
var path = $('#foo').getPath();
// e.g., "html > body > div#bar > ul#abc.def.ghi > li#foo"
回答by crizCraig
Here's a version of Blixt's answer that works in IE:
这是适用于 IE 的 Blixt 答案的一个版本:
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;
};
回答by Ahmet Can Güven
I just wanted to share my version too because it is very clear to understand. I tested this script in all common browsers and it is working like a boss.
我也只是想分享我的版本,因为它很容易理解。我在所有常见的浏览器中测试了这个脚本,它像老板一样工作。
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;
}
回答by algorhythm
Same solution like that one from @Blixt but compatible with multiple jQuery elements.
与@Blixt 的解决方案相同,但与多个 jQuery 元素兼容。
jQuery('.some-selector')can result in one or many DOM elements. @Blixt's solution works unfortunately only with the first one. My solution concatenates all them with ,.
jQuery('.some-selector')可以产生一个或多个 DOM 元素。不幸的是,@Blixt 的解决方案仅适用于第一个。我的解决方案将所有这些与,.
If you want just handle the first element do it like this:
如果您只想处理第一个元素,请这样做:
jQuery('.some-selector').first().getPath();
// or
jQuery('.some-selector:first').getPath();
Improved version
改良版
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(',');
}
});
回答by Konrad Dzwinel
If you are looking for a comprehensive, non-jQuery solution then you should try axe.utils.getSelector.
如果您正在寻找一个全面的非 jQuery 解决方案,那么您应该尝试axe.utils.getSelector。
回答by Develop Ideas
Following up on what alex wrote. jQuery-GetPath is a great starting point but I have modified it a little to incorporate :eq(), allowing me to distinguish between multiple id-less elements.
跟进亚历克斯所写的内容。jQuery-GetPath 是一个很好的起点,但我对它进行了一些修改以合并 :eq(),允许我区分多个 id-less 元素。
Add this before the getPath return line:
在 getPath 返回行之前添加:
if (typeof id == 'undefined' && cur != 'body') {
allSiblings = $(this).parent().children(cur);
var index = allSiblings.index(this);// + 1;
//if (index > 0) {
cur += ':eq(' + index + ')';
//}
}
This will return a path like "html > body > ul#hello > li.5:eq(1)"
这将返回一个类似“html > body > ul#hello > li.5:eq(1)”的路径
回答by Ashraf Sabry
You may also have a look at findCssSelector, which is used in Firefox developer tools to save the currently selected node upon page refreshes. It doesn't use jQuery or any library.
您还可以查看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;
};
回答by pepper69
$.fn.getSelector = function(){
var $ele = $(this);
return '#' + $ele.parents('[id!=""]').first().attr('id')
+ ' .' + $ele.attr('class');
};

