DOM 被操作时究竟更新了什么

What exactly updates when the DOM is manipulated

我想了解在 DOM 操作后使用常规 DOM 更新的确切内容。

假设我们有下面的 DOM,我使用 javascript 删除带有 class 蓝色的 li。

这是否意味着浏览器查看 class blue 的父节点(例如:列表 1 的 ID)并重新呈现 DOM 节点,包括所有子节点(减去 class blue) 然后根据任何 css 规则重新绘制整个页面?

我认为应该是这个过程,但我不确定,也无法在任何地方找到任何具体示例。

 <div>
   <ul id="list1">
     <li> red </li>
     <li class="blue"> blue </li>
     <li> green </li>
    </ul>
    <ul id="list2">
      <li> orange </li>
      <li> gray </li>
      <li> brown </li>
    </ul>
 </div>

是的,因为这是您可以删除元素的唯一方法,......通过它的父元素,即 .removeChild()。 DOM 然后可能会或可能不会进行所谓的回流,具体取决于更改结果。

这并不那么容易,这是因为您可能不太了解 DOM 更新 + 渲染过程 的工作原理。

DOM 只是一个 javascript 对象,与其他对象一样。

当您执行 DOM 操作时,这真的就像您确实修改了一个普通对象的属性(一个复杂的属性,但仍然如此)。

其中一些操作确实会弄脏页面的布局和呈现的框架,但通常浏览器会等到它们确实必须执行重绘操作时才会触发这两种算法。这意味着这些算法不会在每次 DOM 操作时触发。

所以要回答这个问题,当 DOM 被操作时,您正在更改 js 对象的属性,并可能设置一个标志,让它们知道布局重新计算和渲染器,它们必须在下一个屏幕刷新。

当这些 layout recalc (a.k.a reflow) 和 repaint 操作实际启动时不受任何规范约束,并且这是大多数浏览器将尝试优化的地方,因此很难对它们在任何地方的工作方式有一个明确的说法。 (虽然指定 in some cases 回流应该同步启动)。
但是我们可以假设,如果可渲染的内容没有发生任何变化,那么这些至少是捷径。

例如,如果在您的示例中 #list1 将其 display CSS-属性 设置为 none,那么可能没有什么可重新绘制,如果您同步重新附加 .blue 元素,则相同。

简单来说,

// js execution
DOM manip => mark layout as dirty
DOM manip => mark layout as dirty
... there may be a lot here

// Before screen refresh
if(layout.isDirty()) 
  layout.recalc() // will itself mark repaint as dirty if needed
if(renderer.isDirty())
  rendered.repaint()