先看這個固定例子
開始只有一段。先取 querySelectorAll 和 getElementsByTagName 結果,再加第二段、重新查詢。
<style>html{font-size:16px}body{margin:12px;font:1rem/1.5 system-ui,sans-serif;color:#17332d;background:#fff}p{overflow-wrap:anywhere}output{display:block;margin-block:12px;overflow-wrap:anywhere;white-space:pre-wrap}button,input{font:inherit;max-width:100%;box-sizing:border-box}button{margin:4px;padding:8px}label{display:block;margin-block:8px}button:focus-visible,input:focus-visible{outline:3px solid #23715d;outline-offset:2px}ul{padding-inline-start:24px}li{overflow-wrap:anywhere}.highlight{border:2px solid green}</style>
<section id="list"><p>第一則筆記</p></section><output id="result"></output>
<script>const list=document.querySelector('#list');const snapshot=list.querySelectorAll('p');const live=list.getElementsByTagName('p');const added=document.createElement('p');added.textContent='第二則筆記';list.append(added);
const result={snapshot:snapshot.length,live:live.length,current:list.querySelectorAll('p').length};
document.querySelector('#result').textContent=JSON.stringify(result);
console.log(JSON.stringify(result));
</script>{"snapshot":1,"live":2,"current":2}| 核對項目 | 所給輸入或動作 | 結果 |
|---|---|---|
| 加入前先取 querySelectorAll | 原有一段 | snapshot: 1 |
| 加入前先取 getElementsByTagName | 原有一段,再加入一段 | live: 2 |
| 重新查詢 | 加入後 | current: 2 |
原生機制怎樣處理
querySelectorAll 傳回靜態 NodeList,成員維持最初配對的節點;getElementsByTagName 的 HTMLCollection 則會更新。成員固定不等於節點內容已凍結,舊集合內仍是原節點物件。
比較另一寫法
按索引移除即時集合的項目,後面會移位。以下最多三次,移除了 A、C,卻跳過 B。
<style>html{font-size:16px}body{margin:12px;font:1rem/1.5 system-ui,sans-serif;color:#17332d;background:#fff}p{overflow-wrap:anywhere}output{display:block;margin-block:12px;overflow-wrap:anywhere;white-space:pre-wrap}button,input{font:inherit;max-width:100%;box-sizing:border-box}button{margin:4px;padding:8px}label{display:block;margin-block:8px}button:focus-visible,input:focus-visible{outline:3px solid #23715d;outline-offset:2px}ul{padding-inline-start:24px}li{overflow-wrap:anywhere}.highlight{border:2px solid green}</style>
<section id="list"><p>A</p><p>B</p><p>C</p></section><output id="result"></output>
<script>const list=document.querySelector('#list');const live=list.getElementsByTagName('p');const removed=[];for(let index=0;index<3&&index<live.length;index++){removed.push(live[index].textContent);live[index].remove();}
const result={removed,remaining:[...live].map(node=>node.textContent)};
document.querySelector('#result').textContent=JSON.stringify(result);
console.log(JSON.stringify(result));
</script>{"removed":["A","C"],"remaining":["B"]}試清邊界
要移除所給三段,怎樣避免索引移位漏項?
查看參考答案
先取三個節點參照的靜態集合再逐一移除。目前 DOM 變空,但靜態清單仍保留三個已移除節點。
<style>html{font-size:16px}body{margin:12px;font:1rem/1.5 system-ui,sans-serif;color:#17332d;background:#fff}p{overflow-wrap:anywhere}output{display:block;margin-block:12px;overflow-wrap:anywhere;white-space:pre-wrap}button,input{font:inherit;max-width:100%;box-sizing:border-box}button{margin:4px;padding:8px}label{display:block;margin-block:8px}button:focus-visible,input:focus-visible{outline:3px solid #23715d;outline-offset:2px}ul{padding-inline-start:24px}li{overflow-wrap:anywhere}.highlight{border:2px solid green}</style>
<section id="list"><p>A</p><p>B</p><p>C</p></section><output id="result"></output>
<script>const list=document.querySelector('#list');const snapshot=list.querySelectorAll('p');for(const node of snapshot)node.remove();
const result={snapshot:snapshot.length,current:list.querySelectorAll('p').length,firstConnected:snapshot[0].isConnected};
document.querySelector('#result').textContent=JSON.stringify(result);
console.log(JSON.stringify(result));
</script>{"snapshot":3,"current":0,"firstConnected":false}