获取元素的jQueryselect器
在伪代码中,这是我想要的。
var selector = $(this).cssSelectorAsString(); // Made up method... // selector is now something like: "html>body>ul>li>img[3]" var element = $(selector);
原因是我需要把它传递给一个外部环境,在那里一个string是我唯一的方式来交换数据。 这个外部环境需要发回一个结果,以及要更新的元素。 所以我需要能够为页面上的每个元素序列化一个唯一的CSSselect器。
我注意到jQuery中有一个selector
方法,但它似乎不能在这种情况下工作。 它只有在对象是用select器创build的情况下才有效。 如果使用HTML节点对象创build对象,则不起作用。
我现在看到有一个插件存在(与我想到的同名),但这里只是我写的一些快速的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; };
TL; DR – 这是一个比看起来更复杂的问题,你应该使用一个库 。
这个问题乍一看似乎很简单,但是看起来比较棘手,就像用普通的URLreplace链接一样简单 。 一些考虑:
- 使用后代select器与子select器可能会导致select器不唯一的情况 。
- 使用
:eq()
限制了解决scheme的实用性,因为它需要 jQuery - 使用标签+ nth-childselect器可能会导致不必要的长select器
- 不利用id使得select器对页面结构的变化不太健壮 。
进一步certificate问题并不像看起来那么容易:有10个以上的库可以生成CSSselect器,其中一个库的作者已经发表了这个比较 。
jQuery-GetPath是一个很好的开始:它会给你这个项目的祖先,像这样:
var path = $('#foo').getPath(); // eg, "html > body > div#bar > ul#abc.def.ghi > li#foo"
以下是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; };
我只是想分享我的版本,因为它非常清楚地理解。 我在所有常见的浏览器中testing了这个脚本,并且像老板一样工作。
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; }
像@Blixt那样的解决scheme,但与多个jQuery元素兼容。
jQuery('.some-selector')
可以导致一个或多个DOM元素。 @ Blixt的解决scheme不幸的只有第一个。 我的解决scheme将它们连接在一起。
如果你只想处理第一个元素,就像这样做:
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(','); } });
跟随什么亚历克斯写道。 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> body> ul#hello> li.5:eq(1)”的path
如果你正在寻找一个全面的,非jQuery的解决scheme,那么你应该尝试axe.utils.getSelector 。
$.fn.getSelector = function(){ var $ele = $(this); return '#' + $ele.parents('[id!=""]').first().attr('id') + ' .' + $ele.attr('class'); };