【问题标题】:querySelectorAll for grouped data-attributesquerySelectorAll 用于分组数据属性
【发布时间】:2018-11-19 14:29:01
【问题描述】:

假设我有以下标记...

<div data-namespace-title="foo"></div>
<div data-namespace-description="bar"></div>
<div data-namespace-button="foo"></div>

无论如何我可以用querySelectorAll 选择它们吗?

我尝试过document.querySelectorAll([data-namespace-*]),但这当然行不通

【问题讨论】:

  • 标记的副本专门要求 jQuery。这个问题专门询问querySelectorAll

标签: javascript dom


【解决方案1】:

没有简单的方法可以做到这一点,仅仅是因为浏览器没有在属性名称/键上实现通配符选择器(仅在其值上)。您可以做的是简单地遍历您的元素集(在这种情况下,它们的共同点是div),然后将它们过滤掉。

您可以通过调用&lt;Node&gt;.attributes访问每个DOM节点的属性列表,然后将其转换为数组,并检查每个属性的一个或多个name是否与正则表达式模式/^data-namespace-.*/gi匹配:

var els = document.querySelectorAll("div");
var filteredEls = Array.prototype.slice.call(els).filter(function(el) {
  var attributes = Array.prototype.slice.call(el.attributes);
  
  // Determine if attributes matches 'data-namespace-*'
  // We can break the loop once we encounter the first attribute that matches
  for (var i = 0; i < attributes.length; i++) {
    var attribute = attributes[i];
    
    // Return the element if it contains a match, and break the loop
    if (attribute.name.match(/^data-namespace-.*/gi))
        return el;
  }
});

console.log(filteredEls);
<div data-namespace-title="foo">title</div>
<div data-namespace-description="bar">description</div>
<div data-namespace-button="foobar">button</div>
<div data-dummy>dummy</div>

更新:如果你熟悉 ES6,它会变得更简洁,因为:

  • 我们可以使用Array.from 代替繁琐的Array.prototype.slice.call(...)。专业提示:您还可以使用扩展运算符,即const els = [...document.querySelectorAll("div")]
  • 我们可以使用Array.some 来代替手动创建带有返回逻辑的for 循环

const els = Array.from(document.querySelectorAll("div"));
const filteredEls = els.filter(el => {
  const attributes = Array.from(el.attributes);
  
  return attributes.some(attribute => attribute.name.match(/^data-namespace-.*/gi));
});

console.log(filteredEls);
<div data-namespace-title="foo">title</div>
<div data-namespace-description="bar">description</div>
<div data-namespace-button="foobar">button</div>
<div data-dummy>dummy</div>

【讨论】:

    【解决方案2】:

    不确定您是否愿意更改属性的格式,但如果您想使用querySelectorAll,使它们都相同并添加一个额外的属性可能会有所帮助

    Array.from(document.querySelectorAll('[data-namespace]')).forEach(el => {
      console.log(el.getAttribute('data-value'))
    })
    <div data-namespace="title" data-value="foo"></div>
    <div data-namespace="description" data-value="bar"></div>
    <div data-ns="button" data-value="foo"></div>
    <div data-namespace="button" data-value="foo"></div>

    您的另一个选择是使用 xpath。

    注意:当使用iterateNext()时,如果你在调用它之前修改文档将会中断。

    var divs = document.evaluate('//@*[starts-with(name(.), "data-namespace")]', document, null, XPathResult.ANY_TYPE, null);
    
    var div = divs.iterateNext()
    
    while (div) {
      alert(div.ownerElement.textContent)
      div = divs.iterateNext()
    }
    <div data-namespace-title="foo">Foo</div>
    <div data-namespace-description="bar">Bar</div>
    <div data-ns-button="foo">NS Foo</div>
    <div data-namespace-button="foo">Foo</div>

    【讨论】:

      【解决方案3】:

      这种事情没有内置选择器,但您仍然可以轻松完成它,方法是选择所有元素,然后过滤具有以data-namespace 开头的属性的元素:

      console.log(
        [...document.querySelectorAll('*')]
          .filter(({ attributes }) =>
            [...attributes].some(({ name }) => name.startsWith('data-namespace'))
          )
      );
      <div data-baz="baz"></div>
      <div data-namespace-title="foo"></div>
      <div data-namespace-description="bar"></div>
      <div data-namespace-button="foo"></div>

      【讨论】:

        猜你喜欢
        • 2019-04-04
        • 1970-01-01
        • 1970-01-01
        • 2022-10-30
        • 1970-01-01
        • 2018-04-26
        • 1970-01-01
        • 2012-06-02
        相关资源
        最近更新 更多