获取被点击的 <a> 的 DOM 路径

IT技术 javascript jquery html dom css-selectors
2021-03-07 09:40:07

HTML

<body>
<div class="lol">
<a class="rightArrow" href="javascriptVoid:(0);" title"Next image">
</div>
</body>

伪代码

$(".rightArrow").click(function() {
rightArrowParents = this.dom(); //.dom(); is the pseudo function ... it should show the whole
alert(rightArrowParents);
});

警报消息将是:

body div.lol a.rightArrow

我怎样才能用 javascript/jquery 得到这个?

6个回答

这是一个返回 jQuery 路径的原生 JS 版本。如果元素有 ID,我还会为它们添加 ID。如果您在数组中看到一个 id,这将使您有机会执行最短路径。

var path = getDomPath(element);
console.log(path.join(' > '));

输出

body > section:eq(0) > div:eq(3) > section#content > section#firehose > div#firehoselist > article#firehose-46813651 > header > h2 > span#title-46813651

这是功能。

function getDomPath(el) {
  var stack = [];
  while ( el.parentNode != null ) {
    console.log(el.nodeName);
    var sibCount = 0;
    var sibIndex = 0;
    for ( var i = 0; i < el.parentNode.childNodes.length; i++ ) {
      var sib = el.parentNode.childNodes[i];
      if ( sib.nodeName == el.nodeName ) {
        if ( sib === el ) {
          sibIndex = sibCount;
        }
        sibCount++;
      }
    }
    if ( el.hasAttribute('id') && el.id != '' ) {
      stack.unshift(el.nodeName.toLowerCase() + '#' + el.id);
    } else if ( sibCount > 1 ) {
      stack.unshift(el.nodeName.toLowerCase() + ':eq(' + sibIndex + ')');
    } else {
      stack.unshift(el.nodeName.toLowerCase());
    }
    el = el.parentNode;
  }

  return stack.slice(1); // removes the html element
}
就我而言,我必须检查元素 hasAttribute 是否是一个函数:typeof el.hasAttribute === 'function'之前el.hasAttribute('id')
2021-05-03 09:40:07
我同意@Adam,如果有多个相同的元素(ul>li:eq(1)>a),这个函数会针对正确的元素。完美的!
2021-05-05 09:40:07
这个功能运行良好,在我看来比接受的答案更好,因为它允许您为不明确的元素获得唯一的路径。例如,列表项上没有唯一标识符的无序列表。
2021-05-15 09:40:07

使用 jQuery,就像这样(接下来是一个除了事件之外不使用 jQuery 的解决方案;如果这很重要,函数调用就会少很多):

$(".rightArrow").click(function() {
  var rightArrowParents = [];
  $(this).parents().addBack().not('html').each(function() {
    var entry = this.tagName.toLowerCase();
    if (this.className) {
      entry += "." + this.className.replace(/ /g, '.');
    }
    rightArrowParents.push(entry);
  });
  alert(rightArrowParents.join(" "));
  return false;
});

现场示例:

(在实时示例中,我更新classdivto be上的属性lol multi以演示处理多个类。)

它用于parents获取被点击元素的祖先,html从那个 via 中移除元素not(因为你从 开始body),然后循环为每个父元素创建条目并将它们推送到一个数组上。然后我们使用addBacka返回添加到集合中,这也将集合的顺序更改为您想要的(parents很特别,它以您想要的顺序相反的顺序为您提供父母,然后addBAck将其放回 DOM 顺序) . 然后它用于Array#join创建以空格分隔的字符串。

创建条目时,如果有任何内容,className我们将替换空格.以支持具有多个类的元素(<p class='foo bar'>has className= "foo bar",因此条目最终为p.foo.bar)。

为了完整起见,这是 jQuery 可能过度使用的地方之一,您只需走 DOM 就可以轻松做到这一点:

$(".rightArrow").click(function() {
  var rightArrowParents = [],
    elm,
    entry;

  for (elm = this; elm; elm = elm.parentNode) {
    entry = elm.tagName.toLowerCase();
    if (entry === "html") {
      break;
    }
    if (elm.className) {
      entry += "." + elm.className.replace(/ /g, '.');
    }
    rightArrowParents.push(entry);
  }
  rightArrowParents.reverse();
  alert(rightArrowParents.join(" "));
  return false;
});

现场示例:

在那里,我们只是重复使用元素的标准parentNode属性沿着树向上走,直到我们用完父html元素或我们看到元素。然后我们反转我们的数组(因为它反向到你想要的输出),并加入它,我们很高兴。

我想你已经知道你是个坏蛋。谢啦!:)
2021-04-15 09:40:07
对于您的纯 JS 示例, dorightArrowParents.unshift()而不是push()and reverse()?
2021-04-19 09:40:07
@p0lar_bear - 我对此表示怀疑,因为这需要在循环中每次都改组所有属性,而不是在最后改组一次。但我也怀疑这是否重要,因为数量很少。:-)
2021-04-25 09:40:07
@Mike:哈哈,不用担心,很高兴有帮助。
2021-05-02 09:40:07

我需要一个原生 JS 版本,它返回 CSS 标准路径(不是 jQuery),并处理 ShadowDOM。此代码是 Michael Connor 答案的一个小更新,以防万一其他人需要它:

function getDomPath(el) {
  if (!el) {
    return;
  }
  var stack = [];
  var isShadow = false;
  while (el.parentNode != null) {
    // console.log(el.nodeName);
    var sibCount = 0;
    var sibIndex = 0;
    // get sibling indexes
    for ( var i = 0; i < el.parentNode.childNodes.length; i++ ) {
      var sib = el.parentNode.childNodes[i];
      if ( sib.nodeName == el.nodeName ) {
        if ( sib === el ) {
          sibIndex = sibCount;
        }
        sibCount++;
      }
    }
    // if ( el.hasAttribute('id') && el.id != '' ) { no id shortcuts, ids are not unique in shadowDom
    //   stack.unshift(el.nodeName.toLowerCase() + '#' + el.id);
    // } else
    var nodeName = el.nodeName.toLowerCase();
    if (isShadow) {
      nodeName += "::shadow";
      isShadow = false;
    }
    if ( sibCount > 1 ) {
      stack.unshift(nodeName + ':nth-of-type(' + (sibIndex + 1) + ')');
    } else {
      stack.unshift(nodeName);
    }
    el = el.parentNode;
    if (el.nodeType === 11) { // for shadow dom, we
      isShadow = true;
      el = el.host;
    }
  }
  stack.splice(0,1); // removes the html element
  return stack.join(' > ');
}
警告:shadow DOM v1 已放弃对 ::shadow 选择器的支持。没有办法为 shadow DOM 元素生成完整的 CSS 选择器。我建议用错误替换上面的“::shadow”行。
2021-05-15 09:40:07

这是一个元素精确匹配的解决方案。

重要的是要了解chrome 工具显示选择器它不是真正选择器)不能唯一标识 DOM 中的元素。例如它不会区分连续span元素列表。没有定位/索引信息

类似(关于 xpath)答案的改编

$.fn.fullSelector = function () {
    var path = this.parents().addBack();
    var quickCss = path.get().map(function (item) {
        var self = $(item),
            id = item.id ? '#' + item.id : '',
            clss = item.classList.length ? item.classList.toString().split(' ').map(function (c) {
                return '.' + c;
            }).join('') : '',
            name = item.nodeName.toLowerCase(),
            index = self.siblings(name).length ? ':nth-child(' + (self.index() + 1) + ')' : '';

        if (name === 'html' || name === 'body') {
            return name;
        }
        return name + index + id + clss;

    }).join(' > ');

    return quickCss;
};

你可以像这样使用它

console.log( $('some-selector').fullSelector() );

演示在http://jsfiddle.net/gaby/zhnr198y/

我将代码片段从 TJ Crowder 移到了一个很小的 ​​jQuery 插件中。我使用了他的 jQuery 版本,即使他是对的,这完全是不必要的开销,但我只将它用于调试目的,所以我不在乎。

用法:

html

<html>
<body>
    <!-- Two spans, the first will be chosen -->
    <div>
        <span>Nested span</span>
    </div>
    <span>Simple span</span>

    <!-- Pre element -->
    <pre>Pre</pre>
</body>
</html>

Javascript

// result (array): ["body", "div.sampleClass"]
$('span').getDomPath(false)

// result (string): body > div.sampleClass
$('span').getDomPath()

// result (array): ["body", "div#test"]
$('pre').getDomPath(false)

// result (string): body > div#test
$('pre').getDomPath()

存储库

https://bitbucket.org/tehrengruber/jquery.dom.path