在不使用 jQuery 的情况下选择具有“data-xxx”属性的所有元素

Posted

技术标签:

【中文标题】在不使用 jQuery 的情况下选择具有“data-xxx”属性的所有元素【英文标题】:Select all elements with a "data-xxx" attribute without using jQuery 【发布时间】:2011-10-28 09:54:09 【问题描述】:

仅使用纯 javascript,选择所有具有特定 data- 属性(假设为 data-foo)的 DOM 元素的最有效方法是什么。

元素可能不同,例如:

<p data-foo="0"></p><br/><h6 data-foo="1"></h6>

【问题讨论】:

请记住,document.querySelectorAll 不适用于 IE7。您必须创建一个备用脚本,该脚本将 walk DOM 树并检查每个标签中的属性(实际上我不知道 querySelectorAll 有多快,并且会手动检查标签) . @hay 根本无法在纯 css 中选择这些元素。 @JamesHay 因为不是每个环境、公司、站点、编码标准,你有什么,都允许使用 jQuery。 jQuery 并非不可替代。 @Carnix 同意。除非您已经在使用它,否则使用 jQuery 将不再有意义,即使那样我也可能会选择退出。 6 年前,在您的站点中使用 jQuery 更为普遍,支持 IE5-8 更为普遍,而 jQuery 提供的抽象在一个简单的内衬中完成此操作。 我仍然没有看到任何真正适用于 不同 data- 元素的答案,即:data-foo=0data-bar=1 @987654329 @ data-date="20181231" 【参考方案1】:

你可以使用querySelectorAll:

document.querySelectorAll('[data-foo]');

【讨论】:

完美,谢谢!半相关注意:如果要选择名称中带有冒号的属性,则需要将冒号转义(至少在 Chrome 中),如下所示: querySelectorAll('[attribute\\:name]') (参见:@ 987654322@) 这实际上并没有回答问题的标题。我不想选择“data-foo”。我想在“data-foobar”、“data-bar”、“data-name-i-dont-know”中选择“data-*” @gman 原标题的意图被this edit无意中改变了。我现在已经恢复了。【参考方案2】:
document.querySelectorAll("[data-foo]")

将为您提供具有该属性的所有元素。

document.querySelectorAll("[data-foo='1']")

只会得到值为 1 的值。

【讨论】:

你如何设置你得到的元素的值? @StevenAguilar .querySelectorAll() 返回NodeList。如该文档中所述,您可以使用 .forEach() 迭代集合。请注意,这是一个非 IE 解决方案:developer.mozilla.org/en-US/docs/Web/API/…。如果您需要支持 IE,则必须使用常规的 for 循环遍历 NodeList。【参考方案3】:
document.querySelectorAll('data-foo')

获取具有属性 data-foo 的所有元素的列表

如果您想获取具有某些特定值的数据属性的元素,例如

<div data-foo="1"></div>
<div data-foo="2" ></div>

我想获取 data-foo 设置为“2”的 div

document.querySelector('[data-foo="2"]')

但是,如果我想将数据属性值与某个变量的值相匹配,比如我想在 data-foo 属性设置为 i 时获取元素,那么问题来了。

var i=2;

因此您可以使用模板文字动态选择具有特定数据元素的元素

document.querySelector(`[data-foo="$i"]`)

请注意,即使您不在字符串中写入值,它也会像我写的那样转换为字符串

<div data-foo=1></div>

然后在 Chrome 开发者工具中检查该元素,该元素将如下所示

<div data-foo="1"></div>

您也可以通过在控制台中编写以下代码来交叉验证

console.log(typeof document.querySelector(`[data-foo]="$i"`).dataset('dataFoo'))

为什么我写 'dataFoo' 虽然属性是 data-foo 原因数据集属性被转换为 camelCase 属性

我参考了下面的链接

https://developer.mozilla.org/en-US/docs/Web/html/Global_attributes/data-* https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes

这是我在 *** 上的第一个答案,请告诉我如何改进我的答案写作方式。

【讨论】:

【参考方案4】:

Try it → here

    <!DOCTYPE html>
    <html>
        <head></head>
        <body>
            <p data-foo="0"></p>
            <h6 data-foo="1"></h6>
            <script>
                var a = document.querySelectorAll('[data-foo]');

                for (var i in a) if (a.hasOwnProperty(i)) 
                    alert(a[i].getAttribute('data-foo'));
                
            </script>
        </body>
    </html>

【讨论】:

使用 hasOwnProperty 是 2016 年迄今为止对我来说最好的答案,这对于其他迭代方式来说非常快Mdn hasOwnProperty querySelectorAll() 中的 NodeList 是可迭代的(尽管不是数组)。使用for in 循环将遍历长度和项目属性。相反,使用for of 来迭代旨在被迭代的属性【参考方案5】:

Here 是一个有趣的解决方案:它使用浏览器 CSS 引擎为匹配选择器的元素添加一个虚拟属性,然后评估计算的样式以找到匹配的元素:

它会动态创建样式规则 [...] 然后扫描整个文档(使用 很多谴责和 IE 特定但非常快的 document.all) 并获得 每个元素的计算样式。然后我们寻找 foo 结果对象上的属性并检查它是否评估为 “酒吧”。对于每个匹配的元素,我们添加到一个数组中。

【讨论】:

对,我去掉了关于旧浏览器的提示。 是的,很容易错过标签。因为它是 html5,所以我们都建议 document.querySelectorAll (并且 data-* 属性也是 html5 特定的)。【参考方案6】:
var matches = new Array();

var allDom = document.getElementsByTagName("*");
for(var i =0; i < allDom.length; i++)
    var d = allDom[i];
    if(d["data-foo"] !== undefined) 
         matches.push(d);
    

不确定是谁给了我一个-1,但这是证据。

http://jsfiddle.net/D798K/2/

【讨论】:

您的大部分“正确”只是不正确。我很确定有人给了你-1,因为你做了很多额外的工作来获取元素,然后将集合放入一个数组中。当没有任何解释时,我没有给出-1只是不喜欢。 昂贵(页面上的所有元素),也使用数组文字表示法(即[]),并且在它之上,它不起作用。自己看 --> jsbin.com/ipisul/edit#javascript,html 尽管 OP 无论如何都在使用 HTML 5,但带有全局 (*) 选择器的 getElementsByTagName 在较旧的 IE 版本中已损坏。这是递归 DOM 搜索完成工作的地方。从 data-foo 属性映射的 ElementNode 上也没有“data-foo”属性。您正在寻找 dataset 对象(即:node.dataset.foo. @shawndumas - 看起来你所拥有的都是 PEBKAC。 jsfiddle.net/D798K/2。有用。最终,无论如何,我都会为这个答案给自己 -1 - 我错过了 OP 问题中“最有效”的词...... @Brian - jsbin.com/ipisul 对你有用吗?因为你的 jsfiddle 不能在我的(工作场所要求的)ie9 中工作......【参考方案7】:

虽然不如querySelectorAll 漂亮(有很多问题),但这里有一个非常灵活的函数,它递归 DOM 并且应该在大多数浏览器(旧的和新的)中都可以使用。只要浏览器支持您的条件(即:数据属性),您应该能够检索元素。

对于好奇的人:不要费心在 jsPerf 上测试这个和 QSA。 Opera 11 等浏览器会缓存查询并扭曲结果。

代码:

function recurseDOM(start, whitelist)

    /*
    *    @start:        Node    -    Specifies point of entry for recursion
    *    @whitelist:    Object  -    Specifies permitted nodeTypes to collect
    */

    var i = 0, 
    startIsNode = !!start && !!start.nodeType, 
    startHasChildNodes = !!start.childNodes && !!start.childNodes.length,
    nodes, node, nodeHasChildNodes;
    if(startIsNode && startHasChildNodes)
           
        nodes = start.childNodes;
        for(i;i<nodes.length;i++)
        
            node = nodes[i];
            nodeHasChildNodes = !!node.childNodes && !!node.childNodes.length;
            if(!whitelist || whitelist[node.nodeType])
            
                //condition here
                if(!!node.dataset && !!node.dataset.foo)
                
                    //handle results here
                
                if(nodeHasChildNodes)
                
                    recurseDOM(node, whitelist);
                
            
            node = null;
            nodeHasChildNodes = null;
        
    

然后您可以通过以下方式启动它:

recurseDOM(document.body, "1": 1); 表示速度,或者只是 recurseDOM(document.body);

您的规范示例:http://jsbin.com/unajot/1/edit

不同规格的示例:http://jsbin.com/unajot/2/edit

【讨论】:

querySelectorAll 的一系列问题是什么? 我也很想听听这些问题。 现在,我们永远不会知道那是哪一连串。 SO的永恒之谜又一章 对此表示反对。 querySelectorAll api 完全过度编码并且没有必要 这个问题可能有点过头了,但正如 OP 所要求的那样,它是一个编码良好的解决方案,纯香草。如果您还不知道 document.querySelectorAll 与您可以迭代和查找元素的众多其他方法相比有多慢,那么您不应该对此表示反对。我认为这是对可能性的一个很酷的演示,

以上是关于在不使用 jQuery 的情况下选择具有“data-xxx”属性的所有元素的主要内容,如果未能解决你的问题,请参考以下文章

jQuery Mobile,在不使用 data-position="fixed" 的情况下将页脚设置为屏幕底部,这可能吗?

如何在不删除先前相同值的情况下选择具有重复项的列表中的特定数字?

如何使用 Django、Ajax、jQuery 在不刷新页面的情况下提交表单?

有没有办法在不使用 jQuery UI 和 jQuery Mobile 的情况下在 jQuery 中左右滑动 [重复]

如何使用 jQuery 在不刷新页面的情况下更新 cookie 值?

如何在不使用 jquery append 的情况下插入元标记?