我正在构建一个“节点签名”,它将返回如下节点:
div.container>div.row:nth-child(1)>div.list.col-md-6:nth-child(2)
我接近完成它,我只有以下问题:
nth-child
值仅考虑节点是否相同(nodeName),但由于该节点上有ID,而某些类,选择器无法正确,因为在这种情况下,有只有一个div#clients,而不是多个。 (即使在同一级别,也有很多div)。
以下是代码:
function getPath(e) {
var path = [];
if ('path' in e && e.path.length > 0) {
for (var i = 0; i < e.path.length; i++) {
if (e.path[i]) {
path.push(getNodeSignature(e.path[i]));
}
if (e.path[i] === document.body) break;
}
} else {
var node = e.target;
while(node != document.body) {
if (node) {
path.push(getNodeSignature(node));
}
node = node.parentNode;
}
}
path.reverse();
return path.join('>');
}
function getNodeSignature(node) {
var structure = node.nodeName.toLowerCase();
if ('id' in node && node.id) {
structure += '#' + node.id
}
var classes = null;
if ('classList' in node && node.classList.length > 0) {
classes = Array.prototype.slice.call(node.classList);
} else if ('className' in node && node.className) {
var classes = node.className.split(/\s+/);
}
if (classes !== null && classes.length > 0) {
structure += '.' + classes.join('.');
}
var position = getIndexInParent(node);
if (position > 0) {
structure += ':nth-child(' + position + ')';
}
return structure;
}
// The following code doesn't take into consideration the ID and class path
function getIndexInParent(node) {
var children = node.parentNode.childNodes;
var num = 0;
for (var i=0; i<children.length; i++) {
if (children[i]==node) return num;
if (children[i].nodeName == node.nodeName) num++;
}
return -1;
}
这是一个HTML示例:
<div class="container">
<div class="row">
<div class="list col-md-3">Item 1</div>
<div class="list col-md-3">Item 2</div>
<div class="list col-md-6">Item 3</div>
<div class="list col-md-6">Item 4</div>
</div>
<hr />
<div class="row">
<div class="list col-md-3">Item 1</div>
<div class="list col-md-3">Item 2</div>
<div class="list col-md-6">Item 3</div>
<div class="list col-md-6">Item 4</div>
</div>
<hr />
<div class="row">
<div class="list col-md-3">Item 1</div>
<div class="list col-md-3">Item 2</div>
<div class="list col-md-6">Item 3</div>
<div class="list col-md-6">Item 4</div>
</div>
</div>
在这种情况下,如果您点击第二个.row
,第三个div
,则代码应返回以下内容:
div.container>div.row:nth-child(1)>div.list.col-md-6:nth-child(0)
(n-child应为0,而不是3,因为之前的指示,“div”和“.list.col-md-6”足以减少2项的可能性)
示例:https://jsfiddle.net/an2jsq2r/1/
如果您点击第二项,在“第3项”上,您将获得:
body>div.container>div.row:nth-child(1)>div.list.col-md-6:nth-child(2)
哪个错了,因为它应该是:
body>div.container>div.row:nth-child(1)>div.list.col-md-6:nth-child(0)
(注意div.list.col-md-6:nth-child(0)
)。该代码没有考虑电位ID和类添加的限制来计算元素的位置。
我该怎么办? (注意:通过支持最大范围的浏览器,我需要尽可能广泛。)
答案 0 :(得分:0)
示例:https://jsfiddle.net/an2jsq2r/1/
如果您点击第二项,在“第3项”上,您将获得:
body>div.container>div.row:nth-child(1)>div.list.col-md-6:nth-child(2)
哪个错了,因为它应该是:
body>div.container>div.row:nth-child(1)>div.list.col-md-6:nth-child(0)
不,不应该。你误解了:nth-child
。它应该是
body>div.container>div.row:nth-child(3)>div.list.col-md-6:nth-child(3) Note --------------------------------^------------------------------^
...因为第二个div.row
是其父级中的第三个元素,该行中的第一个div.list.col-md-6
是第三个行中的元素。
这是证据:
var path = "body>div.container>div.row:nth-child(3)>div.list.col-md-6:nth-child(3)";
var element = document.querySelector(path);
element.innerHTML = "This one!";
element.style.color = "blue";
<div class="container">
<div class="row">
<div class="list col-md-3">Item 1</div>
<div class="list col-md-3">Item 2</div>
<div class="list col-md-6">Item 3</div>
<div class="list col-md-6">Item 4</div>
</div>
<hr />
<div class="row">
<div class="list col-md-3">Item 1</div>
<div class="list col-md-3">Item 2</div>
<div class="list col-md-6">Item 3</div>
<div class="list col-md-6">Item 4</div>
</div>
<hr />
<div class="row">
<div class="list col-md-3">Item 1</div>
<div class="list col-md-3">Item 2</div>
<div class="list col-md-6">Item 3</div>
<div class="list col-md-6">Item 4</div>
</div>
</div>
正如我所说in this comment,:nth-child
并不关心 关于选择器的其余部分。
更简单的例子:div:nth-child(2)
表示“div也是其父亲中的第二个孩子”。 不意味着“父母的第二个div孩子。”
要确定要使用的正确:nth-child
,您在父级中使用纯粹的基于1的索引,而不考虑完全其他方面,如标记名称,什么它有的课等等。
因此,getIndexInParent
应为:
function getIndexInParent(node) {
var children = node.parentNode.children; // Note: Not `childNodes`
for (var i = 0; i < children.length; i++) { // Note: 0 <= n < length
if (children[i]==node) return i + 1; // Note: No other criteria, and +1 on value
}
return -1;
}
如果我们将其应用于您的小提琴(如果您使用“整页”选项,此代码段效果最佳):
function getPath(e) {
var path = [];
if ('path' in e && e.path.length > 0) {
for (var i = 0; i < e.path.length; i++) {
if (e.path[i]) {
path.push(getNodeSignature(e.path[i]));
}
if (e.path[i] === document.body) break;
}
} else {
var node = e.target;
while(node != document.body) {
if (node) {
path.push(getNodeSignature(node));
}
node = node.parentNode;
}
}
path.reverse();
return path.join('>');
}
function getNodeSignature(node) {
var structure = node.nodeName.toLowerCase();
if ('id' in node && node.id) {
structure += '#' + node.id
}
var classes = null;
if ('classList' in node && node.classList.length > 0) {
classes = Array.prototype.slice.call(node.classList);
} else if ('className' in node && node.className) {
var classes = node.className.split(/\s+/);
}
if (classes !== null && classes.length > 0) {
structure += '.' + classes.join('.');
}
var position = getIndexInParent(node);
if (position > 0) {
structure += ':nth-child(' + position + ')';
}
return structure;
}
function getIndexInParent(node) {
var children = node.parentNode.children; // Note: Not `childNodes`
for (var i = 0; i < children.length; i++) { // Note: 0 <= n < length
if (children[i]==node) return i + 1; // Note: No other criteria, and +1 on value
}
return -1;
}
document.addEventListener('click', function (e) {
var path = getPath(e);
console.log("path is: " + path);
var element = document.querySelector(path);
if (element) {
element.innerHTML = "You clicked me!";
element.style.color= "green";
console.log("updated element");
} else {
console.log("That's weird, no element found!");
}
})
<div class="container">
<div class="row">
<div class="list col-md-3">Item 1</div>
<div class="list col-md-3">Item 2</div>
<div class="list col-md-6">Item 3</div>
<div class="list col-md-6">Item 4</div>
</div>
<hr />
<div class="row">
<div class="list col-md-3">Item 1</div>
<div class="list col-md-3">Item 2</div>
<div class="list col-md-6">Item 3</div>
<div class="list col-md-6">Item 4</div>
</div>
<hr />
<div class="row">
<div class="list col-md-3">Item 1</div>
<div class="list col-md-3">Item 2</div>
<div class="list col-md-6">Item 3</div>
<div class="list col-md-6">Item 4</div>
</div>
</div>
或者,如果我们应用您的:nth-of-type
提示:
function getTypeIndexInParent(node) {
var tag = node.tagName;
var children = node.parentNode.children;
var child;
var num = 0;
for (var i = 0; i < children.length; i++) {
child = children[i];
if (child.tagName === tag) {
++num;
}
if (children[i]==node) return num;
}
return -1;
}
我们得到:
function getPath(e) {
var path = [];
if ('path' in e && e.path.length > 0) {
for (var i = 0; i < e.path.length; i++) {
if (e.path[i]) {
path.push(getNodeSignature(e.path[i]));
}
if (e.path[i] === document.body) break;
}
} else {
var node = e.target;
while(node != document.body) {
if (node) {
path.push(getNodeSignature(node));
}
node = node.parentNode;
}
}
path.reverse();
return path.join('>');
}
function getNodeSignature(node) {
var structure = node.nodeName.toLowerCase();
if ('id' in node && node.id) {
structure += '#' + node.id
}
var classes = null;
if ('classList' in node && node.classList.length > 0) {
classes = Array.prototype.slice.call(node.classList);
} else if ('className' in node && node.className) {
var classes = node.className.split(/\s+/);
}
if (classes !== null && classes.length > 0) {
structure += '.' + classes.join('.');
}
var position = getTypeIndexInParent(node);
if (position > 0) {
structure += ':nth-of-type(' + position + ')';
}
return structure;
}
function getTypeIndexInParent(node) {
var tag = node.tagName;
var children = node.parentNode.children;
var child;
var num = 0;
for (var i = 0; i < children.length; i++) {
child = children[i];
if (child.tagName === tag) {
++num;
}
if (children[i]==node) return num;
}
return -1;
}
document.addEventListener('click', function (e) {
var path = getPath(e);
console.log("path is: " + path);
var element = document.querySelector(path);
if (element) {
element.innerHTML = "You clicked me!";
element.style.color= "green";
console.log("updated element");
} else {
console.log("That's weird, no element found!");
}
})
<div class="container">
<div class="row">
<div class="list col-md-3">Item 1</div>
<div class="list col-md-3">Item 2</div>
<div class="list col-md-6">Item 3</div>
<div class="list col-md-6">Item 4</div>
</div>
<hr />
<div class="row">
<div class="list col-md-3">Item 1</div>
<div class="list col-md-3">Item 2</div>
<div class="list col-md-6">Item 3</div>
<div class="list col-md-6">Item 4</div>
</div>
<hr />
<div class="row">
<div class="list col-md-3">Item 1</div>
<div class="list col-md-3">Item 2</div>
<div class="list col-md-6">Item 3</div>
<div class="list col-md-6">Item 4</div>
</div>
</div>
答案 1 :(得分:-1)
好的,所以为了仅在必要时使用“:nth-of-type”,这意味着只有当其他规则(节点名称+节点id +节点类)对于至少2个孩子来说是相同的时候。< / p>
结果如下:
function getIndexInParent(node) {
if (node === null || node.parentNode === null) return -1;
var children = node.parentNode.childNodes,
freezePosition = false,
position = 1, // 1 based index
quantity = 1; // Already counting the same item
for (var i = 0; i < children.length; i++) {
if (node === children[i]) {
freezePosition = true;
continue;
}
if (node.nodeName === children[i].nodeName) {
if (!freezePosition) position++;
quantity++;
}
}
return (quantity > 1 ? position : -1);
}
function getNodeSignature(node, withoutPosition) {
if (!node || !node.nodeName) return null;
var structure = node.nodeName.toLowerCase();
if (withoutPosition !== false) {
var position = getIndexInParent(node);
if (position > 0) {
return structure + ':nth-of-type(' + position + ')';
}
}
if ('id' in node && node.id) {
structure += '#' + node.id
}
var classes = null;
if ('classList' in node && node.classList.length > 0) {
classes = Array.prototype.slice.call(node.classList);
} else if ('className' in node && node.className) {
var classes = node.className.split(/\s+/);
}
if (classes !== null && classes.length > 0) {
structure += '.' + classes.join('.');
}
return structure;
}
function getPath(e) {
var path = [];
if ('path' in e && e.path.length > 0) {
for (var i = 0; i < e.path.length; i++) {
if (e.path[i] === window.document || e.path[i] === window.document.body) break;
if (e.path[i]) {
path.push(getNodeSignature(e.path[i]));
}
}
} else {
var node = e.target;
while(true) {
if (node === window.document || node === window.document.body) break;
if (node) {
path.push(getNodeSignature(node));
}
node = node.parentNode;
}
}
if (path.length > 0) {
path.reverse();
return 'body>' + path.join('>');
}
return null;
}
如果有人做得更好,我很想知道如何:)