Map(和 WeakMap)更适合处理大量 DOM 节点
import { ref, watchEffect } from 'vue';
- let rowStates = {};
+ let rowStates = new Map();
let activeRow;
document.querySelectorAll('tr').forEach((row) => {
- rowStates[row.id] = ref(false);
+ rowStates.set(row, ref(false));
row.addEventListener('click', () => {
- if (activeRow) rowStates[activeRow].value = false;
+ if (activeRow) rowStates.get(activeRow).value = false;
activeRow = row;
- rowStates[row.id].value = true;
+ rowStates.get(activeRow).value = true;
});
watchEffect(() => {
- if (rowStates[row.id].value) {
+ if (rowStates.get(row).value) {
row.classList.add('active');
} else {
row.classList.remove('active');
}
});
});
明显的好处是不需要担心每行上存在唯一的 ID。节点引用本身——本质上是唯一的——充当键。因此,不需要设置或读取任何属性。它更简单、更有弹性。
WeakMaps更有效地管理内存
<ul>
<li id="item1">first</li>
<li id="item2">second</li>
<li id="item3">third</li>
</ul>
(async () => {
const listMap = new WeakMap();
// Stick each item in a WeakMap.
document.querySelectorAll('li').forEach((node) => {
listMap.set(node, node.id);
});
const registry = new FinalizationRegistry((heldValue) => {
// Garbage collection has happened!
console.log('After collection:', heldValue);
});
registry.register(document.getElementById('item2'), listMap);
console.log('Before collection:', listMap);
// Remove node, freeing up reference!
document.getElementById('item2').remove();
// Periodically create a bunch o' objects to trigger collection.
const objs = [];
while (true) {
for (let i = 0; i < 100; i++) {
objs.push(...new Array(100));
}
await new Promise((resolve) => setTimeout(resolve, 10));
}
})();
原文:https://www.macarthur.me/posts/maps-for-dom-nodes