querySelectorAll 和 getElementsBy* 方法返回什么?

What do querySelectorAll and getElementsBy* methods return?

提问人:dmo 提问时间:5/22/2012 最后编辑:vrintledmo 更新时间:5/3/2023 访问量:104721

问:

(以及类似的函数,如 和 )是否与元素数组相同,或者它们是否返回元素数组?getElementsByClassNamegetElementsByTagNamequerySelectorAllgetElementById

我问的原因是因为我正在尝试使用 .见下文。getElementsByClassName

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

//works
document.getElementById('myIdElement').style.size = '100px';
JavaScript getElementsByClassName DOM-遍历

评论

45赞 David Thomas 5/22/2012
线索很大程度上在于名称:暗示复数,而暗示单数元素项。getElementsByClassName()getElementById()
1赞 dmo 5/22/2012
我明白了,你不能使用上面的代码更改具有该类名的所有元素,而不必遍历数组,这对我来说是没有意义的。jQuery方式要好得多,我只是对JS方式感到好奇
1赞 kapa 7/31/2014
可能也很有用:stackoverflow.com/questions/3871547/......

答:

197赞 ThiefMaster 5/22/2012 #1

getElementById 代码有效,因为 ID 必须是唯一的,因此该函数始终只返回一个元素(或者如果没有找到元素)。null

但是,getElementsByClassName、getElementsByName、getElementsByTagName 和 getElementsByTagNameNS 方法返回可迭代的元素集合。

方法名称提供了提示:表示数,而表示复数getElementgetElements

querySelector 方法还返回单个元素,querySelectorAll 返回一个可迭代集合。

可迭代集合可以是 NodeListHTMLCollection

getElementsByNamequerySelectorAll 都被指定为返回 ;其他 getElementsBy* 方法被指定为返回 ,但请注意,某些浏览器版本以不同的方式实现这一点。NodeListHTMLCollection

这两种集合类型提供的属性与元素、节点或类似类型提供的属性不同;这就是为什么读出......失败。 换句话说:a 或 an 没有 ;只有 an 有一个 .styledocument.getElements()NodeListHTMLCollectionstyleElementstyle


这些“类似数组”的集合是包含零个或多个元素的列表,您需要迭代这些元素才能访问它们。 虽然您可以像数组一样迭代它们,但请注意,它们与数组s 不同

在现代浏览器中,您可以使用 Array.from 将这些可迭代对象转换为适当的 Array;那么你可以使用和其他 Array 方法,例如迭代方法forEach

Array.from(document.getElementsByClassName("myElement"))
  .forEach((element) => element.style.size = "100px");

在不支持或迭代方法的旧浏览器中,您仍然可以使用 Array.prototype.slice.call。 然后,您可以像使用真实数组一样对其进行迭代:Array.from

var elements = Array.prototype.slice
    .call(document.getElementsByClassName("myElement"));

for(var i = 0; i < elements.length; ++i){
  elements[i].style.size = "100px";
}

你也可以遍历 or 本身,但要注意,在大多数情况下,这些集合是实时的(MDN 文档、DOM 规范),即它们会随着 DOM 的变化而更新。 因此,如果您在循环时插入或删除元素,请确保不要意外跳过某些元素创建无限循环。 MDN 文档应始终注意方法返回的是实时集合还是静态集合。NodeListHTMLCollection

例如,a 提供了一些迭代方法,例如在现代浏览器中:NodeListforEach

document.querySelectorAll(".myElement")
  .forEach((element) => element.style.size = "100px");

也可以使用一个简单的循环:for

var elements = document.getElementsByClassName("myElement");

for(var i = 0; i < elements.length; ++i){
  elements[i].style.size = "100px";
}

旁白:.childNodes 产生一个 live,而 .children 产生一个 live ,所以这两个 getter 也需要小心处理。NodeListHTMLCollection


有一些像jQuery这样的库,它使DOM查询更短一些,并在“一个元素”和“元素集合”上创建一个抽象层:

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

评论

2赞 Maduro 9/1/2016
这是否也适用于您域的一部分<iframe>
6赞 4/27/2018
现在是 2018 年......只需创建一个包装函数,您就可以拥有漂亮的短代码,而无需大型的老式依赖项。 也许让包装器收到回调。querySelectorAll()qSA(".myElement").forEach(el => el.style.size = "100px")qSA(".myElement", el => el.style.size = "100px")
3赞 CoryCoolguy 5/9/2019
“如果你喜欢更短的东西,可以考虑在你的项目中添加一个巨大的库” 我知道 2012 年是一个不同的时代,但即便如此,我也会觉得这很荒谬。
4赞 RobG 11/18/2019
"像使用真实数组一样迭代它......注意的是,getElementsByClassName 返回一个实时 NodeList,该 NodeList 可能会在循环过程中被意外修改,例如,如果删除了选择它们的类名。;-)
1赞 Sebastian Simon 7/2/2021
出于各种原因,可能应该从这个答案中删除对 jQuery 的引用:它的行为与原生 DOM 方法有很大不同,它与提出的问题没有直接关系,并且它需要加载一个太大的库,只是为了缩短一两个函数调用。上一个担忧在近十年前是有效的,但随着jQuery失去相关性,今天更加重要。诚然,有些浏览器可能会在内部缓存jQuery,但是我们真的希望新开发人员采用加载一个庞大的库的做法,只是为了使用其中的一小部分吗?
2赞 Matas Vaitkevicius 4/21/2015 #2

对于任何支持 ES5+ 的浏览器(任何基本上高于 IE8 的浏览器),您都可以使用该方法。Array.prototype.forEach

Array.prototype.forEach.call(document.getElementsByClassName('answer'), function(el) {
    el.style.color= 'red';
});

Caniuse 源

13赞 guysigner 1/7/2016 #3

以下描述摘自本页

getElementsByClassName() 方法以 NodeList 对象的形式返回文档中具有指定类名的所有元素的集合。

NodeList 对象表示节点的集合。节点可以是 通过索引号访问。索引从 0 开始。

提示: 可以使用 NodeList 对象的 length 属性来确定具有指定类名的元素数,然后可以遍历所有元素并提取所需的信息。

因此,作为参数将接受类名。getElementsByClassName

如果这是您的 HTML 正文:

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

然后将返回 3 个上 S 的集合(不是数组),因为它们与给定的类名匹配。var menuItems = document.getElementsByClassName('menuItem')<div>

然后,您可以使用以下命令循环访问此节点(在本例中为节点)集合:<div>

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

有关元素和节点之间差异的更多信息,请参阅此帖子

26赞 Alvaro Silvino 2/15/2016 #4

您使用数组作为对象,和之间的区别在于:getElementbyIdgetElementsByClassName

  • getElementbyId将返回一个 Element 对象,如果未找到具有 ID 的元素,则返回 null
  • getElementsByClassName将返回一个实时的 HTMLCollection,如果没有找到匹配的元素,则长度可能为 0

getElementsByClassName

该方法采用一个字符串,该字符串 包含一组无序的唯一空格分隔标记 表示类。调用时,该方法必须返回一个活动对象,其中包含文档中的所有元素 具有该参数中指定的所有类,并获得了 类,通过在空格上拆分字符串。如果没有令牌 在参数中指定,则该方法必须返回一个空 节点列表。getElementsByClassName(classNames)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';

不会按预期工作,因为 将返回一个数组,而该数组将没有属性,您可以通过遍历它们来访问每个数组。getElementByClassNamestyleelement

这就是为什么该函数适合您的原因,此函数将返回直接对象。因此,您将能够进入该物业。getElementByIdstyle

评论

0赞 Kaiido 11/18/2019
请注意,浏览器实现的 whatwg 规范与此处的 w3c 规范不同,前者(以及当前的浏览器)返回 getElementsByClassName 的 HTMLCollection,而不是 NodeList。次要的,但可能会使一些人感到困惑。
1赞 RobG 11/18/2019
@Kaiido——实际的区别是......?根据我的理解,NodeList 是 DOM 元素的通用集合,可用于任何 DOM,而不仅仅是 HTML DOM(例如 XML DOM),而 HTMLCollection 适用于 HTML DOM(显然)。我能看到的唯一区别是 HTMLCollectionnamedItem 方法。
0赞 RobG 11/18/2019
PS Nit pick:WHATWG HTML Living StandardW3C HTML 5.2 标准的链接。被选择宠坏了。;-)不过,对你提出的观点没有区别。
1赞 Kaiido 11/18/2019
@RobG NodeList 有许多在 HTMLCollection 上无法访问的方法。
0赞 RobG 11/18/2019
@Kaiido - 当然,但 forEach 没有被 W3C 或 WHATWG 指定为集合或 NodeList 接口的一部分,它是单独指定的,例如,作为 Web IDL 规范中泛型集合的属性,因此应该适用于集合和 NodeLists(尽管我接受你的观点,即 getElementsByClassName 返回的集合没有 forEach方法)。我想底线是,有足够多的故事可以有一个好的答案来讲述它。:-)
5赞 atilkan 6/17/2016 #5

它返回类似数组的列表。

你把它做成一个数组作为例子

var el = getElementsByClassName("elem");
el = Array.prototype.slice.call(el); //this line
el[0].appendChild(otherElem);  
16赞 kind user 2/22/2017 #6

ES6 提供了 Array.from() 方法,该方法从类似数组或可迭代的对象创建一个新的 Array 实例。

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

setTimeout(() => {
  Array.from(boxes).forEach(v => v.style.background = 'green');
  console.log(Array.from(boxes));
}, 500);
.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赞 Sergey 7/3/2017 #7

你可以通过运行

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

但它适用于类为 .myElement 的第一个元素。

如果你想把它应用于类的所有元素,我建议你使用

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

评论

0赞 lenI 12/16/2021
超级老派解决方案: [].forEach.call(document.getElementsByClassName('myClass'), function (el) { el.style.size = '100px';
8赞 Thielicious 10/23/2017 #8

换句话说

  • document.querySelector()仅选择指定选择器的第一个元素。所以它不会吐出一个数组,它是一个单一的值。与仅获取 ID 元素类似,因为 ID 必须是唯一的。document.getElementById()

  • document.querySelectorAll()选择具有指定选择器的所有元素,并在数组中返回它们。类似于仅适用于类和标记。document.getElementsByClassName()document.getElementsByTagName()


为什么要使用 querySelector?

它仅用于方便和简洁的唯一目的。


为什么使用 getElement/sBy?

更快的性能。


为什么会有这种性能差异?

这两种选择方式都是为了创建一个 NodeList 以供进一步使用。querySelectors 使用选择器生成一个静态 NodeList,因此必须首先从头开始创建它。
getElement/sBy* 会立即适配当前 DOM 的现有实时 NodeList。

因此,何时使用哪种方法取决于您/您的项目/您的设备。


信息

所有方法
的演示 NodeList 文档
性能测试

5赞 Irina Mityugova 11/25/2018 #9
/*
 * 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
-2赞 Cat 7/11/2020 #10

Drenzii 具体案例的答案......

你可以创建一个函数,该函数将适用于任何单词元素,并传入要转换的元素的编号,例如:

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

0赞 lenI 12/16/2021 #11

超级老派的解决方案:

        [].forEach.call(document.getElementsByClassName('myClass'), function (el) {
            el.style.size = '100px';
        });
1赞 MestreALMO 12/26/2021 #12

所以我被告知这是我的问题的副本,我应该删除我的问题,我会这样做,这样我就可以保持论坛清洁并保留提出问题的权利。

由于我认为我的和这个问题确实不同,我会指出我的答案,所以我将完成此页面中的知识,并且信息不会丢失。

问题

  1. 我在代码段中有一个代码,它有一个,在做什么?document.getElementsByClassName("close")[0][0]

  2. 我从未见过方括号用于什么目的?getElementsByClassName

  3. 另外,如何将其转换为jQuery?

  1. 代码段中的代码实际上被用作数组,并且由于它是 0,因此它指的是第一次使用指定的类。[0]

  2. 上面也一样。

  3. 我真的做不到,也没有人回答。在代码中引用我不能使用代替的部分,我认为它们应该是等价的,但是在这种情况下,jQuery表单替换标准表单不会产生预期的效果。event. target$("#myModal")document.getElementById("myModal")

    window.onclick = function(event) {
      if (event.target == modal) {
        modal.style.display = "none";
      }
    }

var modal = document.getElementById("myModal");
var btn = document.getElementById("myBtn");
var span = document.getElementsByClassName("close")[0];

btn.onclick = function() {
  modal.style.display = "block";
}
span.onclick = function() {
  modal.style.display = "none";
}
window.onclick = function(event) {
  if (event.target == modal) {
    modal.style.display = "none";
  }
}
body {font-family: Arial, Helvetica, sans-serif;}

.modal {
  display: none;
  position: fixed;
  z-index: 1;
  padding-top: 100px;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  overflow: auto;
  background-color: rgb(0,0,0);
  background-color: rgba(0,0,0,0.4);
}

.modal-content {
  background-color: #fefefe;
  margin: auto;
  padding: 20px;
  border: 1px solid #888;
  width: 80%;
}

.close {
  color: #aaaaaa;
  float: right;
  font-size: 28px;
  font-weight: bold;
}

.close:hover,
.close:focus {
  color: #000;
  text-decoration: none;
  cursor: pointer;
}
<h2>Modal </h2>

<button id="myBtn">Open Modal</button>

<div id="myModal" class="modal">
  <div class="modal-content">
    <span class="close">&times;</span>
    <p>Some text in the Modal..</p>
  </div>
</div>

更新

看来我真的不能删除我的问题,人们对此不满意,我真的不知道我该怎么办。