เลือกองค์ประกอบทั้งหมดด้วยแอตทริบิวต์“ data-” โดยไม่ใช้ jQuery


233

การใช้ JavaScript เท่านั้นวิธีที่มีประสิทธิภาพที่สุดในการเลือกองค์ประกอบ DOM ทั้งหมดที่มีdata-แอตทริบิวต์ที่แน่นอนคืออะไร (สมมุติว่าdata-foo) องค์ประกอบอาจเป็นองค์ประกอบแท็กที่แตกต่างกัน

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

โปรดทราบว่าdocument.querySelectorAllไม่ทำงานบน IE7 คุณจะต้องสร้างสคริปต์ทางเลือกซึ่งจะเดินทรี DOM และตรวจสอบคุณลักษณะในแต่ละแท็ก (อันที่จริงฉันไม่รู้เลยว่ารวดเร็วแค่ไหนquerySelectorAllและจะไปตรวจสอบแท็กด้วยตนเอง)
tereško

เหตุผลที่คุณไม่ใช้ jQuery คืออะไร มัน irreplacable สวยมากในสถานการณ์เช่นนี้ ...
เจมส์เฮย์

@ ไม่เลยคุณสามารถเลือกองค์ประกอบเหล่านี้ใน CSS บริสุทธิ์ได้เช่นกัน
Knu

1
@JamesHay เพราะไม่ใช่ทุก บริษัท บริษัท ไซต์มาตรฐานการเข้ารหัสสิ่งที่คุณมีอนุญาตให้ใช้ jQuery jQuery ไม่สามารถถูกแทนที่ได้
Carnix

1
ผมยังไม่ได้เห็นคำตอบใด ๆ ที่ได้ผลจริงๆในที่แตกต่างกัน data-องค์ประกอบเช่น: data-foo=0และdata-bar=1 และ data-app="js" และ data-date="20181231"
อเล็กซ์

คำตอบ:


411

คุณสามารถใช้แบบสอบถามเลือกหรือทั้งหมด :

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

8
สมบูรณ์แบบขอบคุณ! หมายเหตุกึ่ง ๆ : หากคุณต้องการเลือกแอททริบิวที่มีโคลอนในชื่อคุณจะต้องหลีกเลี่ยงโคลอน (อย่างน้อยใน Chrome) เช่น: querySelectorAll ('[attribute \\: name]') (ดู: รหัส .google.com / p / chromium / ประเด็น / รายละเอียดหรือไม่ id = 91637 )
Jeremy

243
document.querySelectorAll("[data-foo]")

คุณจะได้รับองค์ประกอบทั้งหมดพร้อมแอตทริบิวต์นั้น

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

คุณจะได้รับสิ่งที่มีค่า 1 เท่านั้น


คุณจะกำหนดค่าสำหรับองค์ประกอบที่คุณได้รับอย่างไร
Steven Aguilar

@StevenAguilar ผลตอบแทน.querySelectorAll() ตามที่ระบุไว้ในเอกสารที่คุณสามารถย้ำกว่าคอลเลกชันโดยใช้NodeList .forEach()หมายเหตุว่านี่เป็นวิธีการแก้ปัญหาที่ไม่ใช่ IE: developer.mozilla.org/en-US/docs/Web/API/... หากคุณต้องการสนับสนุน IE คุณจะต้องวนซ้ำ NodeList โดยใช้การforวนซ้ำปกติ
Joseph Marikle

13

ลอง→ที่นี่

    <!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
NVRM

NodeList จาก querySelectorAll () สามารถทำซ้ำได้ (แม้ว่าไม่ใช่อาร์เรย์) การวนลูปด้วยfor inจะวนซ้ำตามความยาวและคุณสมบัติของรายการ ให้ใช้for ofการวนซ้ำคุณสมบัติที่ออกแบบมาเพื่อทำซ้ำ
Solvitieg

1

นี่เป็นวิธีแก้ปัญหาที่น่าสนใจ: ใช้เครื่องมือ CSS ของเบราว์เซอร์เพื่อเพิ่มคุณสมบัติจำลองเข้ากับองค์ประกอบที่ตรงกับตัวเลือกจากนั้นประเมินสไตล์ที่คำนวณเพื่อค้นหาองค์ประกอบที่ตรงกัน:

มันสร้างกฎสไตล์แบบไดนามิก [... ] จากนั้นจะสแกนเอกสารทั้งหมด (โดยใช้ document.all ที่ decried มากและเฉพาะเจาะจง แต่เร็วมาก) และรับสไตล์ที่คำนวณสำหรับแต่ละองค์ประกอบ จากนั้นเราจะมองหาคุณสมบัติ foo บนวัตถุที่เป็นผลลัพธ์และตรวจสอบว่ามันประเมินว่าเป็น "บาร์" หรือไม่ สำหรับแต่ละองค์ประกอบที่ตรงกันเราเพิ่มเข้าไปในอาร์เรย์


1
ใช่ฉันลบคำใบ้เกี่ยวกับเบราว์เซอร์เก่าออก
Heinrich Ulbricht

ขอบคุณมากครับ;) ฉันต้องสารภาพฉันมองข้าม 5
เฮ็น Ulbricht

ใช่ง่ายที่จะพลาดแท็ก เพราะมันคือ html5 เราทุกคนแนะนำ document.querySelectorAll (และแอตทริบิวต์ data- * เป็น html5 เฉพาะเช่นกัน)
Shawndumas

-1
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/


3
"ถูกต้อง" ของคุณส่วนใหญ่ไม่ถูกต้อง ฉันค่อนข้างแน่ใจว่ามีคนให้ -1 กับคุณเพราะคุณมีงานพิเศษมากมายที่จะได้รับองค์ประกอบจากนั้นจึงใส่ชุดสะสมเข้าไปในอาร์เรย์ ฉันไม่ได้ให้ -1 เพียงแค่ไม่ชอบเมื่อไม่มีคำอธิบายใด ๆ
Loktar

1
แพง (องค์ประกอบทั้งหมดในหน้า) นอกจากนี้ยังใช้สัญกรณ์ตัวอักษรอาร์เรย์ (เช่น []) และด้านบนของมันมันไม่ทำงาน ดูด้วยตัวคุณเอง -> jsbin.com/ipisul/edit#javascript,html
Shawndumas

2
ถึงแม้ว่า OP จะใช้ HTML 5 อยู่ดี แต่ตัวเลือกgetElementsByTagNameglobal ( *) นั้นใช้งานไม่ได้ใน IE builds รุ่นเก่า นี่คือที่ที่การค้นหา DOM แบบเรียกซ้ำทำงานให้เสร็จ นอกจากนี้ยังไม่มีคุณสมบัติ "data-foo" ใน ElementNode ที่แมปจากdata-fooแอตทริบิวต์ คุณกำลังมองหาdatasetวัตถุ (เช่น: node.dataset.foo.

@shawndumas - ปรากฏว่าสิ่งที่คุณมีคือ PEBKAC jsfiddle.net/D798K/2 มันได้ผล. ในที่สุดฉันจะ -1 ตัวเองสำหรับคำตอบนี้ต่อไป - ฉันคิดถึงคำว่า "มีประสิทธิภาพมากที่สุด" ในคำถามของ OP ...
Brian

@Brian - jsbin.com/ipisulทำงานให้คุณได้หรือไม่? ทำให้ jsfiddle ของคุณคนหนึ่งไม่ทำงานในสถานที่ทำงานของฉัน (ต้องการสถานที่ทำงาน) ie9 ...
Shawndumas

-4

แม้ว่าจะไม่สวยเท่าquerySelectorAll(ซึ่งมีปัญหาต่าง ๆ ) นี่เป็นฟังก์ชันที่ยืดหยุ่นมากที่เรียกใช้ DOM ซ้ำและควรทำงานในเบราว์เซอร์ส่วนใหญ่ (เก่าและใหม่) ตราบใดที่เบราว์เซอร์สนับสนุนเงื่อนไขของคุณ (เช่นแอ็ตทริบิวต์ข้อมูล) คุณควรจะสามารถดึงองค์ประกอบได้

สำหรับผู้ที่อยากรู้อยากเห็น: อย่ากังวลกับการทดสอบนี้กับ QSA ใน jsPerf เบราว์เซอร์เช่น 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


23
บทเพลงของปัญหาquerySelectorAllคืออะไร?
ShreevatsaR

9
ฉันชอบที่จะได้ยินเกี่ยวกับปัญหาเหล่านี้
Sean_A91

4
ตอนนี้เราจะไม่มีทางรู้ว่าบทเพลงใดเป็นเพลง อีกหนึ่งบทสำหรับปริศนานิรันดร์จาก SO
brasofilo

downvoting นี้ มันสมบูรณ์มากกว่ารหัสและไม่จำเป็นกับquerySelectorAllapi
dman
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.