querySelectorAll无法正常工作

11

我有一个要求,需要在一个容器中选择最后一个 .div 并对其应用某些业务逻辑。选择最后一个 .div 必须是动态的,因为用户有添加/删除 .div 元素的选项。

最初我尝试使用 querySelectorAll 但似乎没有起作用。所以我决定改用 getElementsByClassName,令人惊讶的是它使用相同的逻辑可以工作。有人可以帮忙解释一下为什么第一个选项(remove_div)不起作用而第二个选项(remove_div_2)可以吗?

注意:我不需要修复/解决问题,因为我已经采用了第二个选项。我只想知道为什么使用 querySelectorAll 的方法无法正常工作。

以下是我的代码:

HTML:

<div id='container'>
    <div id='div1' class='div'>This is Div 1</div>
    <div id='div2' class='div'>This is Div 2</div>
    <div id='div3' class='div'>This is Div 3</div>
</div>
<button type='button' id='append_div'>Append Div</button>
<button type='button' id='remove_div'>Remove Div</button>
<button type='button' id='remove_div_2'>Remove Div 2</button>

JavaScript:

window.onload = function () {
    var elementToStyle = document.querySelectorAll("#container .div");
    elementToStyle[elementToStyle.length - 1].classList.add('red');

    document.getElementById('append_div').onclick = function () {
       var divToInsert = document.createElement('div');
       divToInsert.id = 'new_div';
       divToInsert.className = 'div';
       divToInsert.innerHTML = 'This is an appended div';
       document.getElementById('container').appendChild(divToInsert);
       var elToStyle = document.querySelectorAll("#container .div");
       for (i = 0; i < elToStyle.length; i++)
           elToStyle[i].classList.remove('red');
           elToStyle[elToStyle.length - 1].classList.add('red');
       };

       document.getElementById('remove_div').onclick = function () {
           var elToStyle = document.querySelectorAll("#container .div");
           document.getElementById('container').removeChild(elToStyle[elToStyle.length - 1]);
           elToStyle[elToStyle.length - 1].classList.add('red');
       };

       document.getElementById('remove_div_2').onclick = function () {
           var elToStyle = document.getElementsByClassName('div');
           document.getElementById('container').removeChild(elToStyle[elToStyle.length - 1]);
           elToStyle[elToStyle.length - 1].classList.add('red');
       };
   }
3个回答

16
原因在于querySelectorAll方法返回的是一个静态列表。在使用querySelectorAll之后对文档所做的任何更改(比如这种情况下的removeChild)都不会反映在返回的节点列表中。因此,elToStyle [elToStyle.length - 1]仍将指向被移除的节点。
而另一方面,getElementsByClassName返回的是动态节点列表。这意味着elToStyle [elToStyle.length - 1]将始终指向最后一个.div,无论在准备节点列表后是否对文档进行过任何更改。
以下是官方文档中的摘录,可在此处查看:

由querySelectorAll()方法返回的NodeList对象必须是静态的,而不是实时的([DOM-LEVEL-3-CORE],第1.1.1节)。对底层文档结构的后续更改不得反映在NodeList对象中。这意味着该对象将包含创建列表时在文档中的匹配元素节点的列表。

注意:您可以通过在removeChild之前和之后执行console.log(elToStyle);来查看此情况。

0
如果您想引用最后一个分割元素,请执行以下操作...
var id = 'container';
var d = document.getElementById(id).getElementsByTagName('div')
var lastDiv = d[d.length - 1];

然后应用你的querySelector


4
用户想要获取具有class='div'属性的最后一个元素,因为在问题中它被指定为.div - Harry

-2
你可以使用querySelectorAll()来访问所有的元素,就像这样:
document.querySelectorAll('?').forEach(function(element) {
   // Now you can apply your changes to each element 
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接