代码之家  ›  专栏  ›  技术社区  ›  methodofaction

查询分组数据属性的SelectorAll

  •  0
  • methodofaction  · 技术社区  · 7 年前

    假设我有以下标记…

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

    我是否可以用 querySelectorAll 是吗?

    我试过了 document.querySelectorAll([data-namespace-*]) 但是那当然不行

    3 回复  |  直到 7 年前
        1
  •  1
  •   Terry    7 年前

    没有简单的方法可以做到这一点,因为浏览器不会在属性名/键(仅在其值上)上实现通配符选择器。您可以做的是简单地迭代元素集(在本例中,它们的公分母是 div ,然后过滤掉。

    您可以通过调用 <Node>.attributes ,然后将其转换为数组,并检查每个属性中是否有一个或多个 name 与regex模式匹配 /^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”>标题</DIV>
    <DIV data namespace description=“bar”>说明</DIV>
    <DIV data namespace button=“foobar”>按钮</DIV>
    <DIV数据虚拟化>虚拟化</DIV>
        2
  •  1
  •   Get Off My Lawn    7 年前

    不确定您是否愿意更改属性的格式,但是如果您想使用,可以使它们完全相同并添加一个额外的属性。 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
  •  0
  •   CertainPerformance    7 年前

    对于这样的事情,没有内置的选择器,但是通过选择所有元素,然后筛选那些具有以开头的属性的元素,仍然可以轻松地完成它。 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>