querySelectorAll และ getElementsBy * method ใดที่คืนค่า


151

Do getElementsByClassName(และฟังก์ชั่นที่คล้ายกันเช่นgetElementsByTagNameและquerySelectorAll) การทำงานเช่นเดียวกับgetElementByIdหรือไม่พวกเขากลับอาร์เรย์ขององค์ประกอบอยู่แล้ว?

getElementsByClassNameเหตุผลที่ผมถามเพราะผมกำลังพยายามที่จะเปลี่ยนรูปแบบขององค์ประกอบทั้งหมดที่ใช้ ดูด้านล่าง

//doesn't work
document.getElementsByClassName('myElement').style.size = '100px';

//works
document.getElementById('myIdElement').style.size = '100px';

37
เบาะแสเป็นอย่างมากในชื่อ: getElementsByClassName()หมายถึงพหูพจน์ในขณะที่getElementById()หมายถึงรายการองค์ประกอบเอกพจน์
เดวิดบอกว่าคืนสถานะโมนิก้า

1
ฉันเข้าใจแล้วว่ามันไม่สมเหตุสมผลสำหรับฉันที่คุณไม่สามารถเปลี่ยนองค์ประกอบทั้งหมดด้วยชื่อคลาสนั้นโดยใช้รหัสด้านบนแทนที่จะต้องวนลูปผ่านอาร์เรย์ วิธี jquery ดีกว่ามากฉันแค่อยากรู้อยากเห็นเกี่ยวกับวิธี js
dmo

1
อาจมีประโยชน์เช่นกัน: stackoverflow.com/questions/3871547/…
kapa

คำตอบ:


152

getElementById()รหัสของคุณใช้งานได้เนื่องจาก ID ต้องไม่ซ้ำกันดังนั้นฟังก์ชันจะส่งคืนองค์ประกอบหนึ่งเสมอ (หรือnullหากไม่พบ)

อย่างไรก็ตามgetElementsByClassName(), querySelectorAll()และอื่น ๆgetElementsBy*วิธีการกลับมาเก็บอาร์เรย์เหมือนขององค์ประกอบ พูดซ้ำเหมือนอย่างที่คุณต้องการด้วยอาเรย์จริง:

var elems = document.getElementsByClassName('myElement');
for(var i = 0; i < elems.length; i++) {
    elems[i].style.size = '100px';
}

หากคุณต้องการบางสิ่งที่สั้นกว่าให้ลองใช้jQuery :

$('.myElement').css('size', '100px');

1
ใช้กับ<iframe>สิ่งที่เป็นส่วนหนึ่งของโดเมนของคุณด้วยหรือไม่
JMaster B

3
มันคือปี 2018 ... เพียงแค่สร้างฟังก์ชั่น wrapper สำหรับquerySelectorAll()และคุณสามารถมีรหัสย่อที่ดีโดยไม่ต้องพึ่งพาโรงเรียนขนาดใหญ่ qSA(".myElement").forEach(el => el.style.size = "100px")อาจให้ wrapper ได้รับการติดต่อกลับ qSA(".myElement", el => el.style.size = "100px")

2
"หากคุณต้องการบางสิ่งที่สั้นกว่านี้ลองเพิ่มห้องสมุดขนาดใหญ่ในโครงการของคุณ" ฉันรู้ว่าปี 2012 เป็นช่วงเวลาที่แตกต่างกัน แต่ถึงอย่างนั้นฉันก็จะพบว่าเรื่องนี้น่าหัวเราะ
CoryCoolguy

1
"ทำซ้ำอย่างที่คุณต้องการด้วยอาเรย์จริง ...ระวังgetElementsByClassNameส่งคืนNodeList แบบสดที่อาจแก้ไขโดยไม่คาดคิดระหว่างลูปเช่นถ้าชื่อคลาสที่พวกเขาเลือกถูกลบออก ;-)
RobG

20

คุณกำลังใช้อาร์เรย์เป็นวัตถุความแตกต่างระหว่างgetElementbyIdและ getElementsByClassNameคือ:

  • getElementbyIdจะส่งคืนวัตถุองค์ประกอบหรือเป็นโมฆะหากไม่พบองค์ประกอบที่มี ID
  • getElementsByClassNameจะส่งคืนHTMLCollection แบบสดอาจมีความยาว 0 หากไม่พบองค์ประกอบที่ตรงกัน

getElementsByClassName

getElementsByClassName(classNames)วิธีการใช้เวลาสตริงที่ประกอบด้วยชุดเรียงลำดับของสัญญาณพื้นที่แยกออกจากกันไม่ซ้ำกันเป็นตัวแทนของชั้นเรียน เมื่อเรียกใช้เมธอดต้องส่งคืนNodeListอ็อบเจ็กต์ที่ใช้งานอยู่ ที่มีองค์ประกอบทั้งหมดในเอกสารที่มีคลาสทั้งหมดที่ระบุในอาร์กิวเมนต์นั้นโดยรับคลาสโดยแยกสตริงบนช่องว่าง หากไม่มีโทเค็นที่ระบุในอาร์กิวเมนต์แล้วเมธอดต้องส่งคืน NodeList ที่ว่างเปล่า

https://www.w3.org/TR/2008/WD-html5-20080610/dom.html#getelementsbyclassname

getElementById

เมธอด getElementById () เข้าถึงองค์ประกอบแรกที่มี id ที่ระบุ

https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementById

ในรหัสของคุณบรรทัด:

1- document.getElementsByClassName ('myElement'). style.size = '100px';

จะไม่ทำงานตามที่คาดไว้เพราะgetElementByClassNameจะกลับอาร์เรย์และอาเรย์จะไม่ได้มีstyleคุณสมบัติที่คุณสามารถเข้าถึงแต่ละelementโดย iterating ผ่านพวกเขา

นั่นเป็นเหตุผลที่ฟังก์ชั่นgetElementByIdทำงานให้คุณฟังก์ชั่นนี้จะส่งคืนวัตถุโดยตรง ดังนั้นคุณจะสามารถเข้าถึงstyleคุณสมบัติ


โปรดทราบว่าข้อมูลจำเพาะ whatwgที่นำมาใช้โดยเบราว์เซอร์นั้นแตกต่างจาก w3c ที่นี่ซึ่งเดิม (และเบราว์เซอร์ปัจจุบัน) ส่งคืน HTMLCollection สำหรับ getElementsByClassName ไม่ใช่ NodeList เล็กน้อย แต่อาจสับสนบ้าง
Kaiido

@ Kaiido - ความแตกต่างในทางปฏิบัติคือ…? เพื่อความเข้าใจของฉันNodeListเป็นคอลเลกชันทั่วไปขององค์ประกอบ DOM และมีอยู่ใน DOM ใด ๆ ไม่ใช่แค่ HTML DOM (เช่น XML DOM) ในขณะที่ HTMLCollection สำหรับ HTML DOMs (ชัด) แตกต่างเพียงฉันสามารถดูเป็นnamedItemวิธีการของHTMLCollection
RobG

PS นิตย์รับ: ลิงค์สำหรับWHATWG HTML Living มาตรฐานและW3C HTML 5.2 มาตรฐาน นิสัยเสียโดยการเลือก ;-) ทำให้ไม่มีความแตกต่างไปยังจุดที่คุณยกแม้ว่า
RobG

@RobG NodeList มีหลายวิธีที่ไม่สามารถเข้าถึงได้บน HTMLCollection
Kaiido

@ Kaiido-แน่ใจ แต่forEachไม่ได้ระบุเป็นส่วนหนึ่งของอินเตอร์เฟซสำหรับคอลเลกชันหรือ NodeList โดย W3C หรือ WHATWG ก็ระบุแยกกันเช่นเป็นทรัพย์สินของคอลเลกชันทั่วไปในที่เว็บ IDLเปคจึงควรนำไปใช้กับทั้งคอลเลกชันและ NodeLists (แม้ว่าฉันยอมรับจุดของคุณว่าคอลเลกชันที่ส่งกลับโดยgetElementsByClassNameไม่มีเมธอดforEach ) ฉันเดาว่าสิ่งที่สำคัญที่สุดคือมีเรื่องราวเพียงพอสำหรับคำตอบที่ดีที่จะบอก :-)
RobG

11

คำอธิบายต่อไปนี้นำมาจากหน้านี้ :

เมธอด getElementsByClassName () ส่งคืนคอลเล็กชันขององค์ประกอบทั้งหมดในเอกสารที่มีชื่อคลาสที่ระบุเป็นอ็อบเจ็กต์ NodeList

วัตถุ NodeList แสดงถึงชุดของโหนด โหนดสามารถเข้าถึงได้โดยหมายเลขดัชนี ดัชนีเริ่มต้นที่ 0

เคล็ดลับ: คุณสามารถใช้คุณสมบัติความยาวของวัตถุ NodeList เพื่อกำหนดจำนวนองค์ประกอบที่มีชื่อคลาสที่ระบุจากนั้นคุณสามารถวนซ้ำผ่านองค์ประกอบทั้งหมดและแยกข้อมูลที่คุณต้องการ

ดังนั้นพารามิเตอร์getElementsByClassNameจะยอมรับชื่อคลาส

หากนี่คือเนื้อหา HTML ของคุณ:

<div id="first" class="menuItem"></div>
<div id="second" class="menuItem"></div>
<div id="third" class="menuItem"></div>
<div id="footer"></div>

จากนั้นvar menuItems = document.getElementsByClassName('menuItem')จะส่งคืนคอลเล็กชัน (ไม่ใช่อาร์เรย์) ของ 3 ส่วนบน<div>เนื่องจากตรงกับชื่อคลาสที่ระบุ

จากนั้นคุณสามารถทำซ้ำในโหนดนี้<div>ได้ในคอลเลกชันด้วย:

for (var menuItemIndex = 0 ; menuItems.length ; menuItemIndex ++) {
   var currentMenuItem = menuItems[menuItemIndex];
   // do stuff with currentMenuItem as a node.
}

โปรดอ้างอิงโพสต์นี้สำหรับข้อมูลเพิ่มเติมเกี่ยวกับความแตกต่างระหว่างองค์ประกอบและโหนด


11

ES6จัดเตรียมArray.from()วิธีการซึ่งสร้างอินสแตนซ์ Array ใหม่จากวัตถุที่คล้ายอาร์เรย์หรือทำซ้ำได้

let boxes = document.getElementsByClassName('box');

Array.from(boxes).forEach(v => v.style.background = 'green');
console.log(Array.from(boxes));
.box {
  width: 50px;
  height: 50px;
  margin: 5px;
  background: blue;
  display: inline-block;
}
<div class='box'></div>
<div class='box'></div>
<div class='box'></div>
<div class='box'></div>

อย่างที่คุณเห็นภายในโค้ดขนาดเล็กหลังจากใช้Array.from()ฟังก์ชั่นคุณจะสามารถจัดการกับแต่ละองค์ประกอบได้


jQueryวิธีการแก้ปัญหาเดียวกันโดยใช้

$('.box').css({'background':'green'});
.box {
  width: 50px;
  height: 50px;
  margin: 5px;
  background: blue;
  display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='box'></div>
<div class='box'></div>
<div class='box'></div>
<div class='box'></div>


7

ในคำอื่น ๆ

  • document.querySelector()เลือกเพียงหนึ่งองค์ประกอบแรกของตัวเลือกที่ระบุ ดังนั้นมันจะไม่คายอาร์เรย์ออกมาเป็นค่าเดียว คล้ายกับการdocument.getElementById()ดึงองค์ประกอบ ID เท่านั้นเนื่องจาก ID ต้องไม่ซ้ำกัน

  • document.querySelectorAll()เลือกองค์ประกอบทั้งหมดที่มีตัวเลือกที่ระบุและส่งกลับพวกเขาในอาร์เรย์ คล้ายกับdocument.getElementsByClassName()คลาสและdocument.getElementsByTagName()แท็กเท่านั้น


ทำไมต้องใช้ querySelector

มันใช้เพื่อวัตถุประสงค์เพียงอย่างเดียวของความสะดวกและความกะทัดรัด


ทำไมต้องใช้ getElement / sBy? *

ประสิทธิภาพที่เร็วขึ้น


ทำไมประสิทธิภาพนี้จึงต่างกัน

วิธีการเลือกทั้งสองมีจุดประสงค์ในการสร้างNodeListเพื่อใช้งานต่อไป querySelectorsสร้าง NodeList แบบคงที่ด้วยตัวเลือกดังนั้นมันจะต้องถูกสร้างขึ้นครั้งแรกตั้งแต่เริ่มต้น
getElement / sBy *ปรับใช้ NodeList แบบสดที่มีอยู่ของ DOM ปัจจุบันทันที

ดังนั้นเมื่อใดที่จะใช้วิธีการที่เป็นคุณ / โครงการของคุณ / อุปกรณ์ของคุณ


infos

การสาธิตวิธีการทั้งหมดการทดสอบประสิทธิภาพ
เอกสาร NodeList


4

มันส่งคืนรายการเหมือน Array

คุณทำ Array นั้นเป็นตัวอย่าง

var el = getElementsByClassName("elem");
el = Array.prototype.slice.call(el); //this line
el[0].appendChild(otherElem);  

4

คุณสามารถรับองค์ประกอบเดียวโดยการทำงาน

document.querySelector('.myElement').style.size = '100px';

แต่มันจะใช้งานได้กับองค์ประกอบแรกที่มีคลาส. myElement

หากคุณต้องการใช้สิ่งนี้กับองค์ประกอบทั้งหมดในชั้นเรียนฉันขอแนะนำให้คุณใช้

document.querySelectorAll('.myElement').forEach(function(element) {
    element.style.size = '100px';
});

4
/*
 * To hide all elements with the same class, 
 * use looping to reach each element with that class. 
 * In this case, looping is done recursively
 */

const hideAll = (className, i=0) => {
if(!document.getElementsByClassName(className)[i]){ //exits the loop when element of that id does not exist
  return; 
}

document.getElementsByClassName(className)[i].style.visibility = 'hidden'; //hide element
return hideAll(className, i+1) //loop for the next element
}

hideAll('appBanner') //the function call requires the class name


0

คำตอบสำหรับกรณีเฉพาะของ Drenzii ...

คุณสามารถสร้างฟังก์ชั่นที่ใช้ได้กับwordองค์ประกอบใด ๆและผ่านจำนวนที่คุณต้องการแปลงเช่น:

// Binds `wordButtons` to an (array-like) HTMLCollection of buttons
const wordButtons = document.getElementsByClassName("word");

// Applies the `slantWord` function to the first word button
slantWord(1);

// Defines the `slantWord` function
function slantWord(wordNumber) {
  const index = wordNumber - 1; // Collection index is zero-based
  wordButtons[index].style.transform = "rotate(7deg)"; // Transforms the specified button
}
<div class="wordGameContainer">
  <button class="word word1">WORD 1</button>
  <button class="word word2">WORD 2</button>
  <button class="word word3">WORD 3</button>
  <button class="word word4">WORD 4</button>
</div>

<div>
  <button onclick="moveWord()" class="playButton">PLAY</button>
</div>

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