清空div 使用
replaceChildren
div.replaceChildren()
- 直接清空所有子节点,性能高效。
- 不会影响 div 本身的样式、类、ID 或其他属性。
- 保留占位(div 本身仍在 DOM 树中)。
- 比 innerHTML = '' 更安全,不会触发 HTML 解析。
不推荐使用以下的
div.textContent= ''
div.innerHTML = ''
// 循环删除子节点 效率低下
while (div.firstChild) {
div.removeChild(div.firstChild);
}
DocumentFragment
使用document.querySelector()
docuemnt.querySelectorAll()
替代 getElementById
getElementsByTagName
querySelector
和 querySelectorAll
比传统的 getElementById
或 getElementsByTagName
更灵活。
const items = document.querySelectorAll('.item');
items.forEach(item => item.classList.add('active'));
缓存查询的dom
重复查询 DOM 元素会增加开销,建议缓存结果。
// 低效
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
快速替换所有子节点,性能优于清空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);
}
事件委托
通过事件冒泡,将事件监听器绑定到父元素,而不是每个子元素,减少内存占用。
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'; }
-
避免重复操作
检查是否需要重复执行相同的操作。if (!element.classList.contains('active')) { element.classList.add('active'); }
使用 Web Components 或框架
对于复杂的 DOM 操作,考虑使用 Web Components 或前端框架(如 React、Vue、Svelte)。它们通过封装和虚拟 DOM 优化了性能和代码可维护性。
MutationObserve
/**
* 观察指定容器中是否出现包含特定类名的元素,并执行回调函数
* @param {HTMLElement} container - 要观察的容器元素
* @param {string} targetClass - 要检测的类名
* @param {Function} callback - 检测到目标元素时执行的回调函数,接收找到的元素作为参数
* @param {MutationObserverInit} [config] - 可选的 MutationObserver 配置,默认为 { childList: true, subtree: true }
* @returns {MutationObserver} - 返回 MutationObserver 实例,以便后续可手动断开观察
*/
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 必须是一个函数');
}
// 创建 MutationObserver 回调
const observerCallback = (mutationsList, observer) => {
for (const mutation of mutationsList) {
if (mutation.type === 'childList') {
mutation.addedNodes.forEach(node => {
if (node.nodeType === Node.ELEMENT_NODE) {
// 检查当前节点
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;
}