操作 DOM 时究竟更新了什么

tre*_*ek1 5 javascript css dom dom-manipulation

我试图准确地了解在 DOM 操作后使用常规 DOM 更新了什么。

假设我们有下面的 DOM,我使用 javascript 删除类 blue 的 li。

这是否意味着浏览器查看 blue 类的父级(例如:列表 1 的 id)并重新渲染该 DOM 节点,包括所有子级(减去 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>
Run Code Online (Sandbox Code Playgroud)

Kai*_*ido 4

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

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

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

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

因此,为了回答这个问题,当操作 DOM 时,您将更改 js 对象的属性,并可能设置一个标志,让其知道布局重新计算和渲染器,它们必须在下一次屏幕刷新时启动。

当这些布局重新计算(又名回流)和重绘操作实际上启动时,不受任何规范的约束,并且这正是大多数浏览器将尝试优化的地方,因此很难对这些操作在任何地方如何工作有一个明确的说法。(尽管指定在某些情况下回流应同步启动)。
但我们可以假设,如果可渲染的内容没有发生任何变化,那么这些至少会是捷径。

例如,如果在您的示例中将#list1displayCSS 属性设置为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()
Run Code Online (Sandbox Code Playgroud)