Получение селектора jQuery для элемента
В коде 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 node объекта.
Ответы
Ответ 1
Теперь я вижу, что существует плагин (с тем же именем, о котором я думал), но вот только какой-то быстрый JavaScript, который я написал. Он не учитывает идентификаторы или классы элементов. только структура (и добавляет :eq(x)
, где имя node неоднозначно).
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;
};
Ответ 2
TL; DR - это более сложная проблема, чем кажется, и вы должны использовать .
Эта проблема кажется легкой на первый взгляд, но она сложнее, чем кажется, так же как замена простых URL-ссылок на ссылки нетривиальна. Некоторые соображения:
Дальнейшее доказательство того, что проблема не так проста, как кажется: есть 10 + библиотеки, которые генерируют селектор CSS, а автор одного из них опубликовал это сравнение.
Ответ 3
jQuery-GetPath является хорошей отправной точкой: он даст вам предков, например:
var path = $('#foo').getPath();
// e.g., "html > body > div#bar > ul#abc.def.ghi > li#foo"
Ответ 4
Здесь версия ответа 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 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
Я просто хотел поделиться своей версией, потому что это очень понятно. Я тестировал этот script во всех распространенных браузерах и работал как босс.
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;
}
Ответ 6
То же решение, что и у @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(',');
}
});
Ответ 7
Если вы ищете всеобъемлющее решение, отличное от jQuery, тогда вы должны попробовать axe.utils.getSelector.
Ответ 8
Следуя за тем, что написал alex.
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)"
Ответ 9
Вы также можете взглянуть на 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 unique with a tag name?
selector = cssEscape(tagName) + selector;
matches = document.querySelectorAll(selector);
if (matches.length === 1) {
return selector;
}
// Maybe it 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 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;
};
Ответ 10
$.fn.getSelector = function(){
var $ele = $(this);
return '#' + $ele.parents('[id!=""]').first().attr('id')
+ ' .' + $ele.attr('class');
};