如何为DOM元素生成唯一的css选择器?

时间:2011-12-21 10:23:16

标签: javascript dom css-selectors

我需要为元素生成唯一的css选择器 特别是,我有onclick事件处理程序,应该记住什么目标元素 单击并将此信息发送到我的服务器。有没有办法在不做DOM修改的情况下做到这一点?

P.S。我的javascript代码应该在不同的上运行 第三方网站,所以我不能对html做任何假设。

7 个答案:

答案 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)

您可以将DOM树从节点遍历回body元素以生成选择器。

Firebug有一个功能,使用XPath和CSS选择器。

请参阅this answer

答案 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

Build Status

  • 生成最短的选择器
  • 每页唯一选择器
  • 稳定而强大的选择器
  • 2.9 kB gzip和缩小尺寸

生成的选择器示例:

.blog > article:nth-child(3) .add-comment

答案 6 :(得分:0)

Firefox开发者控制台使用以下试探法来查找元素的唯一选择器。该算法返回找到的第一个合适的选择器。 (Source

  1. 如果元素具有唯一的id属性,请返回ID选择器#<idname>

  2. 如果标记是htmlheadbody,则返回类型选择器<elementname>

  3. 对于元素的每个类:

    1. 如果类对于元素而言是唯一的,则返回类选择器.<classname>

    2. 如果标记/类组合是唯一的,请返回选择器<elementname>.<classname>

    3. 计算元素在其父级的子级列表中的索引。如果选择器<elementname>.<classname>:nth-child(<index>)是唯一的,则返回该选择器。

  4. index作为元素在其父项的子级列表中的索引。

    1. 如果父节点是根节点,则返回选择器<elementname>:nth-child(<index>)

    2. 否则,递归地为父节点找到唯一的选择器,然后返回<parentselector> > <elementname>:nth-child(<index>)