簡體   English   中英

JS DOM操作

[英]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中,那么您所使用的索引(例如,如果i2 )可能不再引用那里的舊元素 - 它可能引用集合中的下一個項目,或者前一個項目,或者甚至可能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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM