【问题标题】:Getting Element Path for selector获取选择器的元素路径
【发布时间】:2012-09-20 13:59:18
【问题描述】:

遇到了麻烦,基本上是在尝试创建一个可以用作选择器的变量。例如

$('a').click(function(){
   var selector = $(this).dompath();
});

HTML:

html
    body
        div
            div /div
        /div
       ul
         li
         li
       /ul
    div
        ul
           li
           li
           li hello world
        /ul
   /div
   body
html

这会返回类似的东西

path = html body div ul li:contains('hello world')

然后我可以在选择器中使用它来选择这个 div 所以如果我喜欢

$(path).text() would return "hello world"

非常感谢!

【问题讨论】:

  • 不同之处在于我不想使用像 :eq(3) 这样的元素的索引,就好像添加了另一个元素一样 eq3 将是错误的,这就是我希望它与内容匹配的原因: )
  • 好的,但是您使用的任何类型的选择器都容易受到 DOM 的某些种更改的影响。例如。如果您使用html body div ul li:contains('hello world'),但添加了另一个包含<li>hello world war ii</li>
      元素,则您的路径可能选择了错误的元素。所以你必须指定你的选择器应该对什么样的差异敏感。
  • 好的,然后用 [where text = hello world] 替换包含会更容易吗??
  • @OwenMelbourne,请尝试理解 LarsH 的评论——您对该评论的回复是您没有理解该评论的证据。

标签: jquery dom xpath element


【解决方案1】:

大概是这样的:

function dompath( element )
{
    var path = '';
    for ( ; element && element.nodeType == 1; element = element.parentNode )
    {
        var inner = $(element).children().length == 0 ? $(element).text() : '';
        var eleSelector = element.tagName.toLowerCase() + 
           ((inner.length > 0) ? ':contains(\'' + inner + '\')' : '');
        path = ' ' + eleSelector + path;
    }
    return path;
}

这修改了另一个问题的方法,只有当标签没有子标签时,才通过:contains() 运算符添加标签的全文内容。

我用这个方法测试过:

$(document).ready(function(){
    $('#p').click(function() {
      console.log(dompath(this));
    });
});

反对:

<html>
    <body>
        <div>
            <div> </div>
        </div>
       <ul>
         <li></li>
         <li></li>
       </ul>
       <div>
         <ul>
           <li id="p">hi</li>
           <li></li>
           <li id="p2">hello world</li>
        </ul>
       </div>
   <body>
<html>

点击p的结果输出为:

html body div ul li:contains('hi')

【讨论】:

    【解决方案2】:

    @jcern`s fantastic code的修改版。

    特点:

    • 如果元素有id:只显示#elementId
    • 如果没有 id:显示element.className
    • 如果不存在类:显示element,并附加innerHtml(如果有)
    • 跳过&lt;body&gt;&lt;html&gt; 元素以缩短输出
    • 不依赖 jQuery
    function dompath(element) {
        var path = '',
        i, innerText, tag, selector, classes;
    
        for (i = 0; element && element.nodeType == 1; element = element.parentNode, i++) {
            innerText = element.childNodes.length === 0 ? element.innerHTML : '';
            tag = element.tagName.toLowerCase();
            classes = element.className;
    
            // Skip <html> and <body> tags
            if (tag === "html" || tag === "body")
                continue;
    
            if (element.id !== '') {
                // If element has an ID, use only the ID of the element
                selector = '#' + element.id;
    
                // To use this with jQuery, return a path once we have an ID
                // as it's no need to look for more parents afterwards.
                //return selector + ' ' + path;
            } else if (classes.length > 0) {
                // If element has classes, use the element tag with the class names appended
                selector = tag + '.' + classes.replace(/ /g , ".");
            } else {
                // If element has neither, print tag with containing text appended (if any)
                selector = tag + ((innerText.length > 0) ? ":contains('" + innerText + "')" : "");
            }
    
            path = ' ' + selector + path;
        }
        return path;
    }
    

    【讨论】:

    • 绝对是我想要的。 +1
    【解决方案3】:

    您需要枚举要为其创建查询的元素的所有父元素,并为每个父元素添加一个选择器,例如父节点名称或包含测试的名称,如果该父节点需要该测试。如果需要此包含测试,唯一确定的方法可能是在每个步骤中针对当前父级应用当前查询并检查查询是否仅返回目标元素。然后添加 contains-test 如果匹配太多...

    我为此写了Greasemonkey script。首先,它收集在另一棵树(“模板”)中查找目标元素所需的所有元素,然后将其转换为查询。但是,它使用属性(特别是 class/id/name )而不是文本进行匹配,以及位置,如果属性不够唯一,因为我认为在大多数情况下,文本的变化比结构更频繁。

    【讨论】:

      【解决方案4】:

      这个请求有点傻,因为有一个很多更好的方法。

      或者为元素分配一个唯一的 ID 以便以后快速引用它,或者如果已经分配了一个 ID,则使用它。

      //
      // generate a unique (enough) id for an element if necessary
      //
      function getUID(id) {
          if(window["uidCounter"]==null)
              window["uidCounter"]=0;
          return id||( (window["uidCounter"]++) + "_" + (new Date()).getTime() );
      }
      //
      // use an #ID selector
      //
      $('a').click(function(){
         var uid = getUID( $(this).attr('id') );
         $(this).attr('id', uid);
         var selector = "#" + uid;
      });
      

      【讨论】:

      • 那么当您稍后返回页面并需要使用我们之前保存到数据库中的选择器来选择不再具有您刚刚保存的id的元素时会发生什么?跨度>
      • @Owen Melbourne - 有趣的想法,也许应该在问题中添加警告,以便其他人可以更好地解释您的“用例”。我会说为您计划引用的所有元素生成正确的唯一“id”将是一件好事。也许你可以使用元素标签名的哈希值和 id 的内容。
      猜你喜欢
      • 2020-12-18
      • 1970-01-01
      • 1970-01-01
      • 2011-12-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-30
      • 2016-06-08
      相关资源
      最近更新 更多