Что возвращают методы querySelectorAll и getElementsBy *?


151

Работают ли 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

1
Также может быть полезно: stackoverflow.com/questions/3871547/…
kapa

Ответы:


152

Ваш getElementById()код работает, поскольку идентификаторы должны быть уникальными, и поэтому функция всегда возвращает ровно один элемент (или, 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 год ... Просто создайте функцию-обертку, querySelectorAll()и вы сможете получить хороший короткий код без большой зависимости от старой школы. qSA(".myElement").forEach(el => el.style.size = "100px")Может быть, чтобы обертка получила обратный звонок. qSA(".myElement", el => el.style.size = "100px")

2
«Если вы предпочитаете что-то более короткое, подумайте о том, чтобы добавить в свой проект огромную библиотеку». Я знаю, что 2012 год был другим, но даже тогда я бы посчитал это смешным.
CoryCoolguy

1
« Итерируйте его, как если бы вы работали с реальным массивом… Осторожно, getElementsByClassName возвращает живой NodeList, который может быть неожиданно изменен во время цикла, например, если имя класса, по которому они были выбраны, удаляется. ;-)
RobG

20

Вы используете массив как объект, разница между getElementbyIdи getElementsByClassNameзаключается в том, что:

  • getElementbyIdвернет объект Element или ноль, если элемент с идентификатором не найден
  • getElementsByClassNameвернет живой HTMLCollection , возможно, длины 0, если не найдено подходящих элементов

getElementsByClassName

getElementsByClassName(classNames)Метод принимает строку , которая содержит неупорядоченный набор уникальных разделенных пробелами лексем , представляющих классы. При вызове метод должен возвращать живой NodeListобъект, содержащий все элементы в документе, которые имеют все классы, указанные в этом аргументе, получив классы, разбив строку на пробелы. Если в аргументе не указаны токены, метод должен вернуть пустой NodeList.

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

getElementById

Метод getElementById () обращается к первому элементу с указанным идентификатором.

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

в вашем коде строки:

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

НЕ будет работать так, как ожидалось, поскольку getElementByClassNameон вернет массив, а массив НЕ будет иметь styleсвойства, к elementкоторому вы можете обращаться , перебирая их.

Вот почему функция getElementByIdработает для вас, эта функция будет возвращать прямой объект. Поэтому вы сможете получить доступ к styleсобственности.


Обратите внимание, что спецификации whatwg , которые реализуются браузерами, отличаются от спецификаций w3c здесь, первые (и, следовательно, текущие браузеры) возвращают HTMLCollection для getElementsByClassName, а не NodeList. Незначительный, но может сбить с толку некоторых.
Кайидо

@ Кайидо - практическая разница ...? Насколько я понимаю, NodeList - это обобщенная коллекция элементов DOM, которая доступна в любом DOM, а не только в HTML DOM (например, XML DOM), тогда как HTMLCollection предназначена для HTML DOM (очевидно). Единственное различие , которое я могу видеть это namedItem метод из HTMLCollection .
RobG

PS Nit выбрать: ссылку на WHATWG HTML Living Standard и стандарт W3C HTML 5.2 . Избалован по выбору. ;-) Не имеет значения к вопросу, который вы подняли, хотя.
RobG

В @RobG NodeList есть много методов , которые недоступны в HTMLCollection.
Кайидо

@ Kaiido - конечно, но forEach не указан как часть интерфейса для коллекции или NodeList от W3C или WHATWG, он указан отдельно, например, как свойство общих коллекций в спецификации Web IDL, поэтому должно применяться как к коллекциям, так и к NodeLists. (хотя я принимаю ваше мнение, что у коллекции, возвращаемой getElementsByClassName , нет метода forEach ). Я предполагаю, что суть в том, что для хорошего ответа достаточно истории. :-)
RobG

11

Следующее описание взято с этой страницы :

Метод getElementsByClassName () возвращает коллекцию всех элементов в документе с указанным именем класса в виде объекта NodeList.

Объект NodeList представляет коллекцию узлов. Доступ к узлам осуществляется по номерам индексов. Индекс начинается с 0.

Совет: Вы можете использовать свойство length объекта 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')вернет коллекцию (не массив) из трех верхних <div>s, поскольку они соответствуют заданному имени класса.

Затем вы можете перебрать эту <div>коллекцию узлов ( в данном случае) с помощью:

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

Пожалуйста, обратитесь к этому сообщению для получения дополнительной информации о различиях между элементами и узлами.


петля выглядит неправильно, должно быть for (var menuItemIndex = 0 ; menuItemIndex < menuItems.length ; menuItemIndex ++) {на мой взгляд.
Дэвид

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-элементы, так как идентификаторы должны быть уникальными.

  • document.querySelectorAll()Выбирает все элементы с указанным селектором и возвращает их в массиве. Аналогично только document.getElementsByClassName()для классов и document.getElementsByTagName()тегов.


Зачем использовать querySelector?

Он используется исключительно с целью простоты и краткости.


Зачем использовать getElement / sBy? *

Быстрее производительность.


Почему эта разница в производительности?

Оба способа выбора имеют целью создание NodeList для дальнейшего использования. querySelectors генерирует статический NodeList с селекторами, поэтому он должен быть сначала создан с нуля.
getElement / Sby * немедленно адаптирует существующий действующий NodeList текущего DOM.

Итак, когда использовать какой метод зависит от вас / вашего проекта / вашего устройства.


Информация

Демо всех методов
NodeList Документация
Тест производительности


4

Возвращает список, похожий на массив.

Вы делаете этот массив как пример

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

Ответ на конкретный случай Дрензии ...

Вы можете создать функцию, которая будет работать для любого из 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>

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.