使用 moveBefore() 在 DOM 變異期間保留狀態

很高興在此宣布,Chrome 133 版推出全新的 moveBefore() DOM API,讓您更輕鬆地在 DOM 中移動元素,且不會遺失狀態。請繼續閱讀,瞭解如何在專案中使用這項功能!

在 DOM 突變期間遺失狀態

您是否使用 appendChild() API 將新元素插入 DOM?許多人都有,但您是否曾經試著呼叫 insertBefore() 或任何其他插入 API,並使用已在 DOM 中的元素?如果是這樣,您可能不知道系統會先從舊父項移除元素,然後重新插入新父項,以便悄悄執行這項操作。這是因為自 1998 年第一版 DOM 標準草案推出以來,Document Object Model 就只有移除和插入原始碼。每當您認為自己在 DOM 中將某些內容從一個位置「移動」到另一個位置時,實際上是在幕後移除和插入

雖然「移動」其實是「移除並插入」,但這對使用者體驗通常不會有任何影響。舉例來說,當您在 DOM 中「移動」<p> 時,這兩個作業不會造成干擾性的副作用,但如果移動儲存重要狀態的複雜節點 (例如 <iframe> 元素、全螢幕元素、CSS 動畫等),隱含的「移除」作業會重設所有狀態。

這可能會造成意想不到的副作用

您可以透過 DOM 樹狀結構中的移動操作,查看在狀態保留示範網站中重設的狀態類型。以下範例顯示從一個父項容器將元素移至另一個父項容器時,CSS 動畫和 <iframe> 狀態重設的情況。

這項限制可能會導致建構動態使用者體驗的難度提高,甚至無法建構。當應用程式狀態莫名重設時,使用者會感到困惑和挫折,而 JavaScript 架構作者則會因此承受重創,因為他們必須花費無數小時,針對這個問題重新架構前端程式碼、編寫 MorphDOM 等複雜的程式庫,或是處理「他們無法修正的問題」的錯誤回報。

新的 moveBefore() API

我們著手修正這個問題,方法是在 DOM 中新增新的原始運算。這個元素適當地稱為「move」原始元素,並透過新的 moveBefore() DOM API 向開發人員公開。

moveBefore() 會採用與 insertBefore() 相同的引數,但在節點已連結至 DOM 時,這個新 API 不會移除及重新插入節點,而是以原子方式移動目標節點至新的父項,且不會重設大部分狀態。這終於讓 JavaScript 開發人員能夠運用可移動的動畫、iframe、全螢幕元素等,打造動態體驗。如要親自試用這項功能,請啟用 chrome://flags/#atomic-move 實驗性標記,並造訪我們的示範網站,或是在 2025 年 2 月 4 日 Chrome 133 版推出後使用該版本。

以下是這個新原始元素可讓 JavaScript 作者達成的行為範例:

  • 在使用者瀏覽網站時保留影片的播放狀態 (無論影片是否由 <video><iframe> 元素提供)。
  • 在 DOM 中移動使用者輸入欄位時,保留該欄位的焦點。
  • 在 DOM 中新增或移除新內容時,讓動畫順利完成。
  • 更高精確度的變形演算法,可將現有的 DOM 與新內容調和。
  • 保持互動式對話方塊、彈出式視窗和全螢幕元素開啟。

我們正努力將這個 API 引進網頁平台,並與其他瀏覽器整合,我們很高興能盡快將這個 API 交給開發人員,滿足開發人員多年來的請求,並填補網頁平台的重大缺口。


和往常一樣,歡迎透過 Twitter 與我們分享您的想法或在下方留言,並將錯誤提交至 crbug.com/new