构建 DOM 中任何给定节点的 querySelector 字符串值
Build the querySelector string value of any given node in the DOM
我正在尝试找到一种方法来构建任何给定节点的 querySelector 字符串。换句话说 - 选择页面上的任何节点 - 是否有可能走上 DOM 并构建一个字符串,允许我将生成的字符串传递给 document.querySelector 并取回我选择的节点?
据我所知,querySelector 有一个错误,您只能在字符串中使用一次 nth-child。
我已经尝试了好几次,但到目前为止都没有找到解决办法。我想在本机 JavaScript 中执行此操作,而不是 jQuery.Any 建议?
我看到这个问题是从 2015 年开始的,但我刚刚处理了这个问题并且不得不构建一个自定义函数来这样做。
我制作了一个片段来测试它,只需单击任何元素,querySelector 应该在底部显示为字符串 div。
function getQuerySelector(elem) {
var element = elem;
var str = "";
function loop(element) {
// stop here = element has ID
if(element.getAttribute("id")) {
str = str.replace(/^/, " #" + element.getAttribute("id"));
str = str.replace(/\s/, "");
str = str.replace(/\s/g, " > ");
return str;
}
// stop here = element is body
if(document.body === element) {
str = str.replace(/^/, " body");
str = str.replace(/\s/, "");
str = str.replace(/\s/g, " > ");
return str;
}
// concat all classes in "queryselector" style
if(element.getAttribute("class")) {
var elemClasses = ".";
elemClasses += element.getAttribute("class");
elemClasses = elemClasses.replace(/\s/g, ".");
elemClasses = elemClasses.replace(/^/g, " ");
var classNth = "";
// check if element class is the unique child
var childrens = element.parentNode.children;
if(childrens.length < 2) {
return;
}
var similarClasses = [];
for(var i = 0; i < childrens.length; i++) {
if(element.getAttribute("class") ==
childrens[i].getAttribute("class")) {
similarClasses.push(childrens[i]);
}
}
if(similarClasses.length > 1) {
for(var j = 0; j < similarClasses.length; j++) {
if(element === similarClasses[j]) {
j++;
classNth = ":nth-of-type(" + j + ")";
break;
}
}
}
str = str.replace(/^/, elemClasses + classNth);
}
else{
// get nodeType
var name = element.nodeName;
name = name.toLowerCase();
var nodeNth = "";
var childrens = element.parentNode.children;
if(childrens.length > 2) {
var similarNodes = [];
for(var i = 0; i < childrens.length; i++) {
if(element.nodeName == childrens[i].nodeName) {
similarNodes.push(childrens[i]);
}
}
if(similarNodes.length > 1) {
for(var j = 0; j < similarNodes.length; j++) {
if(element === similarNodes[j]) {
j++;
nodeNth = ":nth-of-type(" + j + ")";
break;
}
}
}
}
str = str.replace(/^/, " " + name + nodeNth);
}
if(element.parentNode) {
loop(element.parentNode);
}
else {
str = str.replace(/\s/g, " > ");
str = str.replace(/\s/, "");
return str;
}
}
loop(element);
return str;
}
只要 DOM 结构保持不变,它就可以工作。即使 HTML 代码的微小变化也可能导致此函数的结果不正确(根据 return 值)。 因此,它不适用于长期存储 DOM 对 HTML 元素的引用。
function createQuerySelector(element) {
if (element.id) {
return `#${element.id}`;
}
const path = [];
let currentElement = element;
let error = false;
while (currentElement.tagName !== 'BODY') {
const parent = currentElement.parentElement;
if (!parent) {
error = true;
break;
}
const childTagCount= {};
let nthChildFound = false;
for (const child of parent.children) {
const tag = child.tagName;
const count = childTagCount[tag] || 0;
childTagCount[tag] = count + 1;
if (child === currentElement) {
nthChildFound = true;
break;
}
}
if (!nthChildFound) {
error = true;
break;
}
const count = childTagCount[currentElement.tagName];
const tag = currentElement.tagName.toLowerCase();
const selector = `${tag}:nth-of-type(${count})`;
path.push(selector);
currentElement = parent;
}
if (error) {
console.error(element);
throw new Error('Unable to create query selector');
}
path.push('body');
const querySelector = path.reverse().join(' > ');
return querySelector;
}
我正在尝试找到一种方法来构建任何给定节点的 querySelector 字符串。换句话说 - 选择页面上的任何节点 - 是否有可能走上 DOM 并构建一个字符串,允许我将生成的字符串传递给 document.querySelector 并取回我选择的节点?
据我所知,querySelector 有一个错误,您只能在字符串中使用一次 nth-child。
我已经尝试了好几次,但到目前为止都没有找到解决办法。我想在本机 JavaScript 中执行此操作,而不是 jQuery.Any 建议?
我看到这个问题是从 2015 年开始的,但我刚刚处理了这个问题并且不得不构建一个自定义函数来这样做。
我制作了一个片段来测试它,只需单击任何元素,querySelector 应该在底部显示为字符串 div。
function getQuerySelector(elem) {
var element = elem;
var str = "";
function loop(element) {
// stop here = element has ID
if(element.getAttribute("id")) {
str = str.replace(/^/, " #" + element.getAttribute("id"));
str = str.replace(/\s/, "");
str = str.replace(/\s/g, " > ");
return str;
}
// stop here = element is body
if(document.body === element) {
str = str.replace(/^/, " body");
str = str.replace(/\s/, "");
str = str.replace(/\s/g, " > ");
return str;
}
// concat all classes in "queryselector" style
if(element.getAttribute("class")) {
var elemClasses = ".";
elemClasses += element.getAttribute("class");
elemClasses = elemClasses.replace(/\s/g, ".");
elemClasses = elemClasses.replace(/^/g, " ");
var classNth = "";
// check if element class is the unique child
var childrens = element.parentNode.children;
if(childrens.length < 2) {
return;
}
var similarClasses = [];
for(var i = 0; i < childrens.length; i++) {
if(element.getAttribute("class") ==
childrens[i].getAttribute("class")) {
similarClasses.push(childrens[i]);
}
}
if(similarClasses.length > 1) {
for(var j = 0; j < similarClasses.length; j++) {
if(element === similarClasses[j]) {
j++;
classNth = ":nth-of-type(" + j + ")";
break;
}
}
}
str = str.replace(/^/, elemClasses + classNth);
}
else{
// get nodeType
var name = element.nodeName;
name = name.toLowerCase();
var nodeNth = "";
var childrens = element.parentNode.children;
if(childrens.length > 2) {
var similarNodes = [];
for(var i = 0; i < childrens.length; i++) {
if(element.nodeName == childrens[i].nodeName) {
similarNodes.push(childrens[i]);
}
}
if(similarNodes.length > 1) {
for(var j = 0; j < similarNodes.length; j++) {
if(element === similarNodes[j]) {
j++;
nodeNth = ":nth-of-type(" + j + ")";
break;
}
}
}
}
str = str.replace(/^/, " " + name + nodeNth);
}
if(element.parentNode) {
loop(element.parentNode);
}
else {
str = str.replace(/\s/g, " > ");
str = str.replace(/\s/, "");
return str;
}
}
loop(element);
return str;
}
只要 DOM 结构保持不变,它就可以工作。即使 HTML 代码的微小变化也可能导致此函数的结果不正确(根据 return 值)。 因此,它不适用于长期存储 DOM 对 HTML 元素的引用。
function createQuerySelector(element) {
if (element.id) {
return `#${element.id}`;
}
const path = [];
let currentElement = element;
let error = false;
while (currentElement.tagName !== 'BODY') {
const parent = currentElement.parentElement;
if (!parent) {
error = true;
break;
}
const childTagCount= {};
let nthChildFound = false;
for (const child of parent.children) {
const tag = child.tagName;
const count = childTagCount[tag] || 0;
childTagCount[tag] = count + 1;
if (child === currentElement) {
nthChildFound = true;
break;
}
}
if (!nthChildFound) {
error = true;
break;
}
const count = childTagCount[currentElement.tagName];
const tag = currentElement.tagName.toLowerCase();
const selector = `${tag}:nth-of-type(${count})`;
path.push(selector);
currentElement = parent;
}
if (error) {
console.error(element);
throw new Error('Unable to create query selector');
}
path.push('body');
const querySelector = path.reverse().join(' > ');
return querySelector;
}