DOM是浏览器解析HTML生成的实时树状对象结构,document为根节点;它动态同步页面,直接操作本身无错,但频繁触发重排重绘会导致性能瓶颈。
DOM(Document Object Model)是浏览器把 HTML 文档解析后生成的树状对象结构,doc 就是它的根节点。它不是一份静态快照,而是与页面完全同步的“活对象”——你改
umentelement.textContent,页面立刻重绘;你删 node,对应元素马上消失。
这意味着:直接操作 DOM 本身没有错,但频繁、低效地触发重排(reflow)和重绘(repaint)才是性能瓶颈的根源。
innerHTML += 是危险操作?看似方便的拼接写法实际会强制浏览器反复销毁重建子树:
onclick、addEventListener 都失效)正确做法是用文档片段或批量更新:
立即学习“Java免费学习笔记(深入)”;
const fragment = document.createDocumentFragment();
for (let i = 0; i < data.length; i++) {
const li = document.createElement('li');
li.textContent = data[i];
fragment.appendChild(li);
}
listElement.appendChild(fragment); // 仅一次真实 DOM 插入
textContent vs innerText:选错就踩坑二者都设文本,但行为差异极大:
textContent:纯字符写入,不解析 HTML,保留所有空白符,读取时返回所有文本节点(含 script、style 内容)innerText:受 CSS 影响(如 display: none 元素内容不计入),会折叠空白,且在某些浏览器中触发重排除非明确需要模拟用户可见文本(比如做可访问性摘要),否则一律用 textContent。写入富文本?用 insertAdjacentHTML() 替代 innerHTML,更可控:
el.insertAdjacentHTML('beforeend', 'Hello');
只要读取了某些布局相关属性(如 offsetHeight、getBoundingClientRect()、scrollLeft),浏览器就会立刻计算当前样式并执行重排——如果前后夹着 DOM 修改,就形成“重排-修改-重排”恶性循环。
解决方法是把读操作和写操作分开:
现代方案可用 requestAnimationFrame() 或 ResizeObserver 延迟到下一帧,但最稳的仍是手动分离读写逻辑。
DOM 操作本身不慢,慢的是你没意识到浏览器什么时候被迫停下主线程去算布局。