รับองค์ประกอบตามแอตทริบิวต์เมื่อ querySelectorAll ไม่พร้อมใช้งานโดยไม่ใช้ไลบรารี?


123
<p data-foo="bar">

คุณจะเทียบเท่ากับ

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

ที่querySelectorAllคือไม่สามารถใช้งาน ?

ฉันต้องการโซลูชันดั้งเดิมที่ใช้งานได้อย่างน้อยใน IE7 ฉันไม่สนใจ IE6


ตรวจสอบไลบรารีตัวเลือกจาวาสคริปต์sizzle.js
ยุค

1
ดีใช่สิ่งเดียวที่ฉันต้องทำคือแอตทริบิวต์ข้อมูลดังนั้นฉันจึงพยายามหาวิธีที่ง่ายที่สุดในการแก้ไขโดยไม่ต้องดึงเอ็นจิ้นตัวเลือกทั้งหมดเช่น Sizzle แต่จุดที่ดีที่จะดูในแหล่งที่มา BTW เครื่องมือเลือกที่ยอดเยี่ยมอีกตัวคือgithub.com/ded/qwery
ryanve

@ryanve ขอบคุณฉันจะใช้เวลาดู :)
ยุค

โซลูชันการทำงานที่ฉันใช้อยู่ในgithub.com/ryanve/dope/blob/master/dope.jsในวิธีการที่เรียกว่า 'queryAttr'
ryanve

7
ฮ่า ๆ คำถามของคุณคือคำตอบของฉัน ดังนั้นจึงมาพร้อมกับคำถามอื่น ในสถานการณ์ใดที่querySelectorAllไม่สามารถใช้ได้? note - I don't care all IE
vzhen

คำตอบ:


136

คุณสามารถเขียนฟังก์ชันที่เรียกใช้ getElementsByTagName ('*') และส่งคืนเฉพาะองค์ประกอบเหล่านั้นด้วยแอตทริบิวต์ "data-foo":

function getAllElementsWithAttribute(attribute)
{
  var matchingElements = [];
  var allElements = document.getElementsByTagName('*');
  for (var i = 0, n = allElements.length; i < n; i++)
  {
    if (allElements[i].getAttribute(attribute) !== null)
    {
      // Element exists with attribute. Add to array.
      matchingElements.push(allElements[i]);
    }
  }
  return matchingElements;
}

จากนั้น

getAllElementsWithAttribute('data-foo');

8
การใช้!= nullเป็นวิธีที่ดีที่สุด (ดีกว่าความคิดเห็นของฉันด้านบน) เนื่องจากใน IE เก่าเป็นไปได้ที่ getAttribute จะส่งคืนค่าที่typeofเป็น'number'
ryanve

1
ทำไมต้องใช้document.getElementsByTagName('*')แทนdocument.all?
pedrozath

1
ทำไมไม่ใช้hasAttributeมากกว่าgetAttribute() !== nullเพราะคุณต้องการตรวจสอบการมีอยู่เท่านั้นไม่ใช่มูลค่าของมัน?
rvighne

61

ใช้

//find first element with "someAttr" attribute
document.querySelector('[someAttr]')

หรือ

//find all elements with "someAttr" attribute
document.querySelectorAll('[someAttr]') 

เพื่อค้นหาองค์ประกอบตามแอตทริบิวต์ ตอนนี้ได้รับการสนับสนุนในเบราว์เซอร์ที่เกี่ยวข้องทั้งหมด (แม้แต่ IE8): http://caniuse.com/#search=queryselector


2
วิธีนี้มีการโหวตเพิ่มจำนวนมากได้อย่างไรเมื่อคำถามร้องขออย่างชัดเจน: "ฉันต้องการโซลูชันแบบเนทีฟที่ใช้งานได้อย่างน้อยใน IE7 " ประการที่สองลิงก์ดังกล่าวระบุว่าการสนับสนุนเริ่มต้นใน IE11 แม้ว่าจะเริ่มจาก IE8 จริง ๆ - บางทีสิ่งนี้ควรเปลี่ยนเป็นdeveloper.mozilla.org/en-US/docs/Web/API/Element/…ดังนั้นจึงรองรับคำตอบได้จริง .. ?
Zze

7
เหตุผลสำหรับ upvotes ทั้งหมดและเหตุผลที่ฉันทำคำตอบคือว่าคำถามนี้จึงเป็นจริงๆเก่าดังนั้นเมื่อคุณค้นหาวิธีการหาองค์ประกอบ DOM คุณพบว่าคำถามนี้สูงมากในผลการค้นหาและเพราะมันเป็นสิ่งที่คน กำลังมองหาพวกเขาเพิ่มคะแนน ประโยชน์> ความถูกต้องทางประวัติศาสตร์ ประการที่สองลิงก์ยังคงใช้งานได้ดีเพียงแค่นั้น caniuse.com ได้ซ่อนเบราว์เซอร์เก่าไว้หากคุณเปลี่ยนเป็น "การใช้งานสัมพัทธ์" คุณจะยังคงเห็นเบราว์เซอร์เก่า
Pylinux

ทำงานได้อย่างสมบูรณ์แบบ ง่ายและรวดเร็ว
Dawson B

มันคือปี 2020 นี่ควรเป็นคำตอบที่ยอมรับได้ในตอนนี้
NearHuscarl

44

ฉันเล่นไปหน่อยและจบลงด้วยวิธีแก้ปัญหาที่หยาบคายนี้:

function getElementsByAttribute(attribute, context) {
  var nodeList = (context || document).getElementsByTagName('*');
  var nodeArray = [];
  var iterator = 0;
  var node = null;

  while (node = nodeList[iterator++]) {
    if (node.hasAttribute(attribute)) nodeArray.push(node);
  }

  return nodeArray;
}

การใช้งานค่อนข้างง่ายและใช้งานได้แม้ใน IE8:

getElementsByAttribute('data-foo');
// or with parentNode
getElementsByAttribute('data-foo', document);

http://fiddle.jshell.net/9xaxf6jr/

แต่ฉันแนะนำให้ใช้querySelector/ Allสำหรับสิ่งนี้ (และเพื่อรองรับเบราว์เซอร์รุ่นเก่าให้ใช้polyfill ):

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

ใช่ +1 สำหรับ querySelectorAll การทดสอบ jsperf รวดเร็วjsperf.com/custom-vs-selectorall-attributesแสดงให้เห็นว่ามันเป็นเร็วกว่าคำตอบที่ได้รับการยอมรับ ... แต่น่าเสียดายที่มันไม่เข้ากันได้ IE 7 :(
เซบาสเตียนแดเนียล

11

ลองใช้งานได้

document.querySelector ( '[แอตทริบิวต์ = "ค่า"])

ตัวอย่าง:

document.querySelector('[role="button"]')

5

ที่ได้ผลเช่นกัน:

document.querySelector([attribute="value"]);

ดังนั้น:

document.querySelector([data-foo="bar"]);

2
สิ่งนี้ไม่มีเครื่องหมายคำพูดเดียวในตัวเลือกแบบสอบถามจริง ควรจะเป็น: document.querySelector('[data-foo="bar"]');
Brettins

1

ลองสิ่งนี้ - ฉันเปลี่ยนคำตอบข้างต้นเล็กน้อย:

var getAttributes = function(attribute) {
    var allElements = document.getElementsByTagName('*'),
        allElementsLen = allElements.length,
        curElement,
        i,
        results = [];

    for(i = 0; i < allElementsLen; i += 1) {
        curElement = allElements[i];

        if(curElement.getAttribute(attribute)) {
            results.push(curElement);
        }
    }

    return results;
};

จากนั้น

getAttributes('data-foo');

3
คุณเปลี่ยนอะไรและทำไม?
Artjom B.

1

การแก้ไขเล็กน้อยในคำตอบของ @kevinfahy เพื่ออนุญาตให้รับแอตทริบิวต์ตามค่าหากจำเป็น:

function getElementsByAttributeValue(attribute, value){
  var matchingElements = [];
  var allElements = document.getElementsByTagName('*');
  for (var i = 0, n = allElements.length; i < n; i++) {
    if (allElements[i].getAttribute(attribute) !== null) {
      if (!value || allElements[i].getAttribute(attribute) == value)
        matchingElements.push(allElements[i]);
    }
  }
  return matchingElements;
}

0

อย่าใช้ในเบราว์เซอร์

ในเบราว์เซอร์ใช้document.querySelect('[attribute-name]').

แต่ถ้าคุณกำลังทดสอบหน่วยและโดมที่ถูกเยาะเย้ยของคุณมีการใช้งาน QuerySelector ที่ไม่ชัดเจนสิ่งนี้จะช่วยแก้เคล็ด

นี่คือคำตอบของ @ kevinfahy เพียงแค่ตัดทอนให้เล็กลงด้วยฟังก์ชัน ES6 fat arrow และโดยการแปลง HtmlCollection เป็นอาร์เรย์โดยมีค่าใช้จ่ายในการอ่าน

ดังนั้นมันจะใช้ได้กับทรานสไพเลอร์ ES6 เท่านั้น นอกจากนี้ฉันไม่แน่ใจว่ามันจะมีประสิทธิภาพเพียงใดเมื่อมีองค์ประกอบมากมาย

function getElementsWithAttribute(attribute) {
  return [].slice.call(document.getElementsByTagName('*'))
    .filter(elem => elem.getAttribute(attribute) !== null);
}

และนี่คือตัวแปรที่จะได้รับแอตทริบิวต์ที่มีค่าเฉพาะ

function getElementsWithAttributeValue(attribute, value) {
  return [].slice.call(document.getElementsByTagName('*'))
    .filter(elem => elem.getAttribute(attribute) === value);
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.