[英]JS DOM manipulation
我遇到了一個有趣的錯誤,其中elt
未定義為對switchToReady
一些調用。 似乎setTimeout
的函數兩次傳遞相同的DOM節點。
function switchToReady(elt) {
elt.setAttribute('transform', 'translate(17, 0)');
elt.classList.remove('compiling');
}
const compilingElts = document.getElementsByClassName('compiling');
for (let i = 0; i < compilingElts.length; i++) {
const randTime = Math.round(Math.random() * (2000 - 500)) + 500;
setTimeout(() => {
switchToReady(compilingElts[i]);
}, randTime);
}
getElementsByClassName
返回一個實時集合,這意味着如果集合中的元素類在迭代時發生更改,或者如果您將另一個元素添加到DOM中,那么您所使用的索引(例如,如果i
是2
)可能不再引用那里的舊元素 - 它可能引用集合中的下一個項目,或者前一個項目,或者甚至可能undefined
。 這種行為非常不直觀,所以我建議使用querySelectorAll
,它返回一個靜態 NodeList
,當你迭代它時它不會改變。
const compilingElts = document.querySelectorAll('.compiling');
querySelectorAll
其他好處:
它作為參數接受的選擇器字符串可以非常靈活 - 它不僅限於類
在較新的瀏覽器中,您可以直接在NodeList
上調用forEach
,從而無需手動迭代並跟蹤指示:
compilingElts.forEach((elm) => { const randTime = Math.round(Math.random() * (2000 - 500)) + 500; setTimeout(() => { switchToReady(elm); }, randTime); });
在許多情況下,數組方法比for
循環更好。 使用從getElementsByClassName
生成的HTMLCollection
在舊版瀏覽器上實現類似功能的一種方法是使用Array.prototype.forEach
:
Array.prototype.forEach.call(
compilingElts,
(elm) => {
// do stuff with elm
}
);
(一個捷徑是使用[].forEach.call
代替,這將用更少的代碼完成同樣的事情,但引用Array.prototype
有點清楚IMO)
getElementsByClassName
返回一個實時列表,正如您所注意到的,這意味着如果從元素中刪除該類,則列表將更改(其大小)。
您可以使用document.querySelectorAll('.compiling')
來返回一個不活動的列表。
愚蠢的錯誤。 實現了通過刪除類,它正在改變引用的compilingElts
對象的內容和索引。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.