清空div 使用
replaceChildren
div.replaceChildren()
- 直接清空所有子節(jié)點,性能高效。
- 不會影響 div 本身的樣式、類、ID 或其他屬性。
- 保留占位(div 本身仍在 DOM 樹中)。
- 比 innerHTML = '' 更安全,不會觸發(fā) HTML 解析。
不推薦使用以下的
div.textContent= ''
div.innerHTML = ''
// 循環(huán)刪除子節(jié)點 效率低下
while (div.firstChild) {
div.removeChild(div.firstChild);
}
DocumentFragment
使用document.querySelector()
docuemnt.querySelectorAll()
替代 getElementById
getElementsByTagName
querySelector
和 querySelectorAll
比傳統(tǒng)的 getElementById
或 getElementsByTagName
更靈活。
const items = document.querySelectorAll('.item');
items.forEach(item => item.classList.add('active'));
緩存查詢的dom
重復查詢 DOM 元素會增加開銷,建議緩存結(jié)果。
// 低效
document.querySelector('.container').innerHTML = 'Content';
document.querySelector('.container').classList.add('show');
// 高效
const container = document.querySelector('.container');
container.innerHTML = 'Content';
container.classList.add('show');
使用closest 和matches
closest
用于查找最近的祖先元素,matches
用于檢查元素是否符合某個選擇器,簡化事件委托。
document.addEventListener('click', e => {
if (e.target.matches('.btn')) {
console.log('Button clicked');
}
const parent = e.target.closest('.container');
if (parent) {
console.log('Found parent container');
}
});
使用模板字符串+ insertAdjacentHTML/innerHTML
-
使用dataSet classList insertAdjacentHTML
比直接操作className
更安全、簡潔。element.classList.add('active'); element.classList.remove('inactive'); element.classList.toggle('visible');
element.dataset.id = '123'; console.log(element.dataset.id); // '123'
比
innerHTML
更靈活,允許在指定位置插入 HTML。element.insertAdjacentHTML('beforeend', '<div>New content</div>');
-
repalceChidren
快速替換所有子節(jié)點,性能優(yōu)于清空innerHTML
再添加。const parent = document.querySelector('.container'); const newChild = document.createElement('div'); parent.replaceChildren(newChild);
異步操作DOM
對于大型 DOM 操作,使用 requestAnimationFrame
或 setTimeout
分割任務,避免阻塞主線程。
function updateLargeList(items) {
let index = 0;
function processChunk() {
const fragment = document.createDocumentFragment();
for (let i = 0; i < 100 && index < items.length; i++, index++) {
const li = document.createElement('li');
li.textContent = items[index];
fragment.appendChild(li);
}
document.querySelector('ul').appendChild(fragment);
if (index < items.length) {
requestAnimationFrame(processChunk);
}
}
requestAnimationFrame(processChunk);
}
事件委托
通過事件冒泡,將事件監(jiān)聽器綁定到父元素,而不是每個子元素,減少內(nèi)存占用。
document.querySelector('ul').addEventListener('click', e => {
if (e.target.tagName === 'LI') {
console.log(e.target.textContent);
}
});
批量修改樣式
避免逐個修改樣式,而是通過修改 CSS 類或使用 style.cssText
一次性設置。
// 低效
element.style.color = 'red';
element.style.fontSize = '16px';
// 高效
element.classList.add('new-class');
// 或
element.style.cssText = 'color: red; font-size: 16px;';
避免不必要的 DOM 操作
-
檢查元素是否存在
在操作元素前,確保其存在,避免錯誤。const element = document.querySelector('.item'); if (element) { element.textContent = 'Updated'; }
-
避免重復操作
檢查是否需要重復執(zhí)行相同的操作。if (!element.classList.contains('active')) { element.classList.add('active'); }
使用 Web Components 或框架
對于復雜的 DOM 操作,考慮使用 Web Components 或前端框架(如 React、Vue、Svelte)。它們通過封裝和虛擬 DOM 優(yōu)化了性能和代碼可維護性。
MutationObserve
/**
* 觀察指定容器中是否出現(xiàn)包含特定類名的元素,并執(zhí)行回調(diào)函數(shù)
* @param {HTMLElement} container - 要觀察的容器元素
* @param {string} targetClass - 要檢測的類名
* @param {Function} callback - 檢測到目標元素時執(zhí)行的回調(diào)函數(shù),接收找到的元素作為參數(shù)
* @param {MutationObserverInit} [config] - 可選的 MutationObserver 配置,默認為 { childList: true, subtree: true }
* @returns {MutationObserver} - 返回 MutationObserver 實例,以便后續(xù)可手動斷開觀察
*/
export function observeClassInContainer(container, targetClass, callback, config = { childList: true, subtree: true }) {
// 驗證輸入
if (!(container instanceof HTMLElement)) {
throw new Error('container 必須是一個有效的 HTML 元素');
}
if (typeof targetClass !== 'string' || targetClass.trim() === '') {
throw new Error('targetClass 必須是一個非空字符串');
}
if (typeof callback !== 'function') {
throw new Error('callback 必須是一個函數(shù)');
}
// 創(chuàng)建 MutationObserver 回調(diào)
const observerCallback = (mutationsList, observer) => {
for (const mutation of mutationsList) {
if (mutation.type === 'childList') {
mutation.addedNodes.forEach(node => {
if (node.nodeType === Node.ELEMENT_NODE) {
// 檢查當前節(jié)點
if (node.classList.contains(targetClass)) {
callback(node);
}
// 檢查所有子代
const elements = node.querySelectorAll(`.${targetClass}`);
elements.forEach(element => callback(element));
}
});
}
}
};
// 初始化并啟動 MutationObserver
const observer = new MutationObserver(observerCallback);
observer.observe(container, config);
return observer;
}