querySelectorAll 和 getElementsBy* 方法返回什么?

IT技术 javascript getelementsbyclassname dom-traversal
2020-12-26 21:27:26

DO getElementsByClassName(等类似的功能getElementsByTagNamequerySelectorAll)的工作一样getElementById,还是他们返回元素的数组?

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

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

//works
document.getElementById('myIdElement').style.size = '100px';
6个回答

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

但是,方法 getElementsByClassNamegetElementsByNamegetElementsByTagNamegetElementsByTagNameNS 返回一个可迭代的元素集合。

方法名称提供了提示:getElement隐含单数,而getElements隐含复数

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

可迭代集合可以是 aNodeList或 an HTMLCollection

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

这两种集合类型都没有提供元素、节点或类似类型所提供的相同属性;这就是为什么读style的关document.getElements... (...)失败。换句话说: aNodeList或 anHTMLCollection没有style; 只有一个Element有一个style


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

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

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

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

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

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

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

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

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";
}

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

$(".myElement").css("size", "100px");
现在是 2018 年……只需为其创建一个包装函数querySelectorAll(),您就可以拥有漂亮的短代码,而无需大量的老式依赖。qSA(".myElement").forEach(el => el.style.size = "100px")也许让包装器接收回调。qSA(".myElement", el => el.style.size = "100px")
2021-02-07 21:27:26
这是否也适用于<iframe>您的域的一部分
2021-02-20 21:27:26
“如果你喜欢更短的东西,可以考虑在你的项目中添加一个巨大的库”我知道 2012 年是一个不同的时期,但即便如此,我也会发现这有点可笑。
2021-02-25 21:27:26
出于各种原因,对 jQuery 的引用可能应该从这个答案中删除:它的行为与本机 DOM 方法明显不同,它与所提出的问题没有直接关系,并且它需要加载一个太大的库来缩短一两个函数调用。最后一个问题在大约十年前就已经成立,但随着 jQuery 正在失去相关性,今天它变得更加重要。诚然,一些浏览器可能会在内部缓存 jQuery,但我们真的希望新开发人员采用加载庞大库的做法,只是为了使用其中的一小部分吗?
2021-02-26 21:27:26
"像使用真正的数组一样迭代它......小心,getElementsByClassName返回一个可能在循环期间意外修改活动NodeList,例如,如果它们被选择的类名被删除。;-)
2021-03-01 21:27:26

您使用的阵列为对象,之间的差getElementbyIdgetElementsByClassName是:

  • getElementbyId如果没有找到具有 ID 的元素,将返回一个Element 对象或 null
  • 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通过遍历它们来访问每个

这就是该函数getElementById对您有用的原因,该函数将返回直接对象。因此,您将能够访问该style属性。

@Kaiido——实际区别是……?据我了解,NodeList是 DOM 元素的通用集合,可用于任何 DOM,而不仅仅是 HTML DOM(例如 XML DOM),而 HTMLCollection 用于 HTML DOM(显然)。我能看到的唯一区别是namedItem的方法的HTMLCollection
2021-02-06 21:27:26
请注意,浏览器正在实现whatwg 规范与此处的 w3c规范不同,前者(以及当前的浏览器)为 getElementsByClassName 返回 HTMLCollection,而不是 NodeList。轻微,但可能会混淆一些。
2021-02-10 21:27:26
PS Nit 选择:WHATWG HTML Living StandardW3C HTML 5.2 标准的链接被选择宠坏了。;-) 与您提出的观点没有区别。
2021-02-15 21:27:26
@Kaiido——当然,但是forEach没有被 W3C 或 WHATWG 指定为集合或 NodeList 接口的一部分,它是单独指定的,例如作为Web IDL规范中通用集合的属性,因此应该同时适用于集合和 NodeList (尽管我接受您的观点,即getElementsByClassName返回的集合没有forEach方法)。我想最重要的是,有足够的故事来讲述一个好的答案。:-)
2021-02-16 21:27:26
@RobG NodeList 有许多在 HTMLCollection 上无法访问的方法
2021-02-27 21:27:26

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>

以下描述取自此页面

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>

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

然后,您可以使用以下命令迭代此节点(<div>在本例中为 s)集合:

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

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

换句话说

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

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


为什么要使用 querySelector?

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


为什么要使用 getElement/sBy?*

更快的性能。


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

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

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


资讯

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