querySelectorAll 和 getElementsBy* 方法返回啥?

Posted

技术标签:

【中文标题】querySelectorAll 和 getElementsBy* 方法返回啥?【英文标题】:What do querySelectorAll and getElementsBy* methods return?querySelectorAll 和 getElementsBy* 方法返回什么? 【发布时间】:2022-01-21 02:03:52 【问题描述】:

getElementsByClassName(以及类似的函数,如getElementsByTagNamequerySelectorAll)与getElementById 的工作方式相同,还是返回一个元素数组?

我问的原因是因为我正在尝试使用getElementsByClassName 更改所有元素的样式。见下文。

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

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

【问题讨论】:

线索非常多,就在名称中:getElementsByClassName() 表示复数,而getElementById() 表示单数元素项。 我明白了,您不能使用上面的代码更改具有该类名的所有元素,而不必遍历数组,这对我来说没有任何意义。 jquery方式好多了,我只是对js方式很好奇 也可能有用:***.com/questions/3871547/… 【参考方案1】:

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

然而,方法 getElementsByClassName, getElementsByName, getElementsByTagName,和 getElementsByTagNameNS 返回一个可迭代的元素集合。

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

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

可迭代集合可以是NodeListhtmlCollection

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

这两种集合类型都没有提供元素、节点或类似类型提供的相同属性;这就是为什么从document.getElements...(...) 读取style 失败的原因。 换句话说:NodeListHTMLCollection 没有style;只有Elementstyle


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

在现代浏览器中,您可以使用Array.from 将这些可迭代对象转换为适当的数组;那么你可以使用forEach和其他Array methods, e.g. iteration methods:

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 docs、DOM spec),即它们是随着 DOM 的变化而更新。 因此,如果您在循环时插入或删除元素,请确保不会意外skip over some elements 或create an infinite loop。 MDN 文档应始终注意方法返回实时集合还是静态集合。

例如,NodeList 在现代浏览器中提供了一些迭代方法,例如 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");

【讨论】:

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

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

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

caniuse source

【讨论】:

【参考方案3】:

以下描述摘自this page:

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 个上部 &lt;div&gt;s 的集合(不是数组),因为它们与给定的类名匹配。

然后您可以使用以下命令遍历此节点(在本例中为 &lt;div&gt;s)集合:

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

有关元素和节点之间的差异的更多信息,请参阅this post。

【讨论】:

【参考方案4】:

你使用的是数组作为对象,getElementbyIdgetElementsByClassName 是:

getElementbyId 将返回 Element object 或 null 如果没有找到具有 ID 的元素 getElementsByClassName 将返回一个 live HTMLCollection,如果没有找到匹配的元素,长度可能为 0

getElementsByClassName

getElementsByClassName(classNames) 方法接受一个字符串 包含一组无序的唯一空格分隔标记 代表类。调用时,该方法必须返回一个 live 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';

NOT 会按预期工作,因为 getElementByClassName 将返回一个数组,并且该数组将 NOT 具有 style 属性,您可以访问每个 @ 987654340@ 通过遍历它们。

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

【讨论】:

请注意,浏览器正在实现的whatwg specs 与此处的 w3c 不同,前者(以及当前的浏览器)返回一个 HTMLCollection 用于 getElementsByClassName,而不是 NodeList。轻微,但可能会混淆一些人。 @Kaiido——实际的区别是……?据我了解,NodeList 是 DOM 元素的通用集合,可用于任何 DOM,而不仅仅是 HTML DOM(例如 XML DOM),而 HTMLCollection 用于 HTML DOM(显然)。我能看到的唯一区别是HTMLCollectionnamedItem 方法。 PS Nit pick:WHATWG HTML Living StandardW3C HTML 5.2 standard 的链接。被选择宠坏了。 ;-) 对你提出的观点没有影响。 @RobG NodeList 有 many methods 在 HTMLCollection 上无法访问。 @Kaiido — 当然,但是 forEach 没有被 W3C 或 WHATWG 指定为集合或 NodeList 接口的一部分,它是单独指定的,例如作为Web IDL specification 中通用集合的属性,因此 应该 适用于集合和 NodeLists(尽管我接受您的观点,即 getElementsByClassName 返回的集合没有forEach 方法)。我想底线是有足够的故事来讲述一个好的答案。 :-)【参考方案5】:

它返回类似数组的列表。

你以数组为例

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

【讨论】:

【参考方案6】:

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>

正如您在代码 sn-p 中看到的那样,在使用 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('.myElement').style.size = '100px';

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

如果您想将此应用于该类的所有元素,我建议您使用

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

【讨论】:

超级老派解决方案:[].forEach.call(document.getElementsByClassName('myClass'), function (el) el.style.size = '100px'; );【参考方案8】:

换句话说

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

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

为什么要使用 querySelector?

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

为什么要使用 getElement/sBy?*

更快的性能。

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

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

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

信息

Demo of all methodsNodeList DocumentationPerformance Test

【讨论】:

【参考方案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

【讨论】:

【参考方案10】:

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>

【讨论】:

【参考方案11】:

超级老派解决方案:

        [].forEach.call(document.getElementsByClassName('myClass'), function (el) 
            el.style.size = '100px';
        );

【讨论】:

以上是关于querySelectorAll 和 getElementsBy* 方法返回啥?的主要内容,如果未能解决你的问题,请参考以下文章

querySelectorAll 和 getElementsBy* 方法返回啥?

getelementbyid 和 queryselector 获取的区别

querySelector与getElementBy的区别

使用 Javascript 获取元素的继承(级联)祖先 CSS 类

queryAll 和 querySelectorAll 有啥区别

js动态查询指定class名的所有元素,querySelectorAll()和querySelectorAll()的区别