我们很高兴地宣布,Chrome 133 版中推出了新的 moveBefore()
DOM API,可让您更轻松地在 DOM 中移动元素,而不会丢失状态。请继续阅读,了解如何在项目中使用它!
在 DOM 更改期间丢失状态
您是否使用 appendChild()
API 将新元素插入 DOM?许多人都有过这样的疑问,但您是否曾尝试使用 DOM 中已有的元素调用它(或 insertBefore()
,或者任何其他插入 API)?如果是这样,您可能没有意识到,此操作会先从旧父元素中移除元素,然后将其重新插入新父元素,从而静默运行。这是因为自 1998 年引入第一个 DOM 标准草稿以来,文档对象模型就只有移除和插入基元。每当您认为自己在 DOM 中将某个内容从一个位置“移动”到另一个位置时,实际上是在后台移除和插入。
事实上,“移动”实际上是“移除并插入”,这通常不会影响用户体验。例如,在 DOM 中“移动”<p>
时,这两项操作不会产生干扰性副作用,但当移动包含重要状态的复杂节点(例如 <iframe>
元素、全屏元素、CSS 动画等)时,隐式“移除”操作会重置所有类型的状态。
这可能会产生令人惊讶的破坏性副作用
您可以通过在 DOM 树中尝试移动,在我们的状态保留演示网站中查看会重置哪种状态。以下示例展示了从一个父容器将元素移至另一个父容器时,CSS 动画和 <iframe>
状态的重新设置。
这一限制可能会导致构建动态用户体验变得困难甚至不可能。当应用状态神秘地重置时,用户会感到沮丧和困惑,而 JavaScript 框架作者则要承担这方面的重担,他们需要花费无数小时围绕此问题重新构建前端代码、编写 MorphDOM 等复杂库,或者处理突出显示他们无法解决的问题的 bug 报告。
新的 moveBefore()
API
我们决定通过向 DOM 添加新的基元操作来解决此问题。它被恰当地称为“move”基元,并通过新的 moveBefore()
DOM API 向开发者公开。
moveBefore()
采用与 insertBefore()
相同的参数,但与在节点已附加到 DOM 时移除并重新插入节点不同,这个新 API 会原子地移动目标节点到新的父节点,而不会重置大多数状态。这样一来,JavaScript 开发者终于可以使用可移动的动画、iframe、全屏元素等构建动态体验了。您可以通过启用 chrome://flags/#atomic-move
实验性标志并访问我们的演示网站,或在 Chrome 133 版于 2025 年 2 月 4 日发布后使用该版本,亲自试用此功能。
借助这个新基元,JavaScript 作者可以实现以下行为:
- 在用户浏览网站时保留视频的播放状态(无论视频是通过
<video>
还是<iframe>
元素提供)。 - 在 DOM 中移动用户输入字段时,保留其焦点。
- 允许在 DOM 中添加或移除新内容时顺利完成动画。
- 更高保真度的变形算法,用于将现有 DOM 与新内容进行协调。
- 让模态对话框、弹出式窗口和全屏元素保持打开状态。
我们正在努力将此 API 引入到其他浏览器的 Web 平台,很高兴能够尽快将其交到开发者手中,满足开发者多年来的请求,并填补 Web 平台中的重要空白。
一如既往,您可以通过 Twitter 或下方的评论与我们分享您的想法,并通过 crbug.com/new 提交 bug。