我需要为元素生成唯一的css选择器 特别是,我有onclick事件处理程序,应该记住什么目标元素 单击并将此信息发送到我的服务器。有没有办法在不做DOM修改的情况下做到这一点?
P.S。我的javascript代码应该在不同的上运行 第三方网站,所以我不能对html做任何假设。
答案 0 :(得分:4)
是的,你可以这样做。但有几点需要注意。为了能够保证选择器是唯一的,您需要使用不受普遍支持的:nth-child()
。如果您想将这些CSS选择器放入CSS文件中,它将无法在所有浏览器中使用。
我会这样做:
function () {
if (this.id) {
return sendToServer('#' + this.id);
}
var parent = this.parentNode;
var selector = '>' + this.nodeName + ':nth-child(' + getChildNumber(this) ')';
while (!parent.id && parent.nodeName.toLowerCase() !== 'body') {
selector = '>' + this.nodeName + ':nth-child(' + getChildNumber(parent) + ')' + selector;
parent = parent.parentNode;
}
if (parent.nodeName === 'body') {
selector = 'body' + selector;
} else {
selector = '#' + parent.id + selector;
}
return sendToServer(selector);
}
然后将其添加到您要建模的每个元素的单击处理程序中。我将让你实施getChildNumber()
。
修改:刚刚看到您对第三方代码的评论...所以您可以添加event
参数,将this
的所有实例替换为{{1}然后只需将函数附加到event.target
的点击事件,如果这更容易。
答案 1 :(得分:3)
这个函数创建了一个很长但非常实用的独特选择器,可以快速工作。
const getCssSelector = (el) => {
let path = [], parent;
while (parent = el.parentNode) {
path.unshift(`${el.tagName}:nth-child(${[].indexOf.call(parent.children, el)+1})`);
el = parent;
}
return `${path.join(' > ')}`.toLowerCase();
};
示例结果:
html:nth-child(1) > body:nth-child(2) > div:nth-child(1) > div:nth-child(1) > main:nth-child(3) > div:nth-child(2) > p:nth-child(2)
以下代码创建了一个更漂亮和更短的选择器
const getCssSelectorShort = (el) => {
let path = [], parent;
while (parent = el.parentNode) {
let tag = el.tagName, siblings;
path.unshift(
el.id ? `#${el.id}` : (
siblings = parent.children,
[].filter.call(siblings, sibling => sibling.tagName === tag).length === 1 ? tag :
`${tag}:nth-child(${1+[].indexOf.call(siblings, el)})`
)
);
el = parent;
};
return `${path.join(' > ')}`.toLowerCase();
};
示例结果:
html > body > div > div > main > div:nth-child(2) > p:nth-child(2)
答案 2 :(得分:1)
答案 3 :(得分:1)
为简单起见,假设您有一个链接列表:您可以简单地在所有元素的集合中传递触发元素的索引
<a href="#">...</a>
<a href="#">...</a>
<a href="#">...</a>
js(jQuery 1.7+,我使用.on()
否则使用bind()
)函数可以
var triggers = $('a');
triggers.on('click', function(e) {
e.preventDefault();
var index = triggers.index($(this));
/* ajax call passing index value */
});
这样如果你点击第三个元素索引值传递将是2.(基于0的索引);
当然,只要代码(DOM)没有改变,这就是有效的。稍后您可以使用该索引为该元素创建一个css规则,例如使用:nth-child
否则,如果每个元素都有不同的属性(如id),则可以传递该属性
关于JsFiddle的例子:http://jsfiddle.net/t7J8T/
答案 4 :(得分:1)
"use strict";
function getSelector(_context){
var index, localName,pathSelector, that = _context, node;
if(that =='null') throw 'not an dom reference';
index = getIndex(that);
while(that.tagName){
pathSelector = that.localName+(pathSelector?'>'+pathSelector :'');
that = that.parentNode;
}
pathSelector = pathSelector+':nth-of-type('+index+')';
return pathSelector;
}
function getIndex(node){
var i=1;
var tagName = node.tagName;
while(node.previousSibling){
node = node.previousSibling;
if(node.nodeType === 1 && (tagName.toLowerCase() == node.tagName.toLowerCase())){
i++;
}
}
return i;
}
document.addEventListener('DOMContentLoaded', function(){
document.body.addEventListener('mouseover', function(e){
var c = getSelector(e.target);
var element = document.querySelector(c);
//console.log(element);
console.log(c);
//element.style.color = "red"
});
});
你可以尝试这个。不使用jquery。
答案 5 :(得分:1)
检查此CSS选择器生成器库@medv/finder
生成的选择器示例:
.blog > article:nth-child(3) .add-comment
答案 6 :(得分:0)
Firefox开发者控制台使用以下试探法来查找元素的唯一选择器。该算法返回找到的第一个合适的选择器。 (Source)
如果元素具有唯一的id
属性,请返回ID选择器#<idname>
。
如果标记是html
,head
或body
,则返回类型选择器<elementname>
。
对于元素的每个类:
如果类对于元素而言是唯一的,则返回类选择器.<classname>
。
如果标记/类组合是唯一的,请返回选择器<elementname>.<classname>
。
计算元素在其父级的子级列表中的索引。如果选择器<elementname>.<classname>:nth-child(<index>)
是唯一的,则返回该选择器。
让index
作为元素在其父项的子级列表中的索引。
如果父节点是根节点,则返回选择器<elementname>:nth-child(<index>)
。
否则,递归地为父节点找到唯一的选择器,然后返回<parentselector> > <elementname>:nth-child(<index>)
。