语法
moveBefore(movedNode, referenceNode)
参数
movedNode
-
一个
Node
,表示要移动的节点。请注意,这必须是一个Element
或CharacterData
节点。 referenceNode
-
一个
Node
,movedNode
将被移动到此节点之前;或者为null
。如果值为null
,movedNode
将插入到调用节点的子节点的末尾。
返回值
无(undefined
)。
异常
HierarchyRequestError
TypeError
-
在以下任何情况下抛出:
- 指定的
movedNode
不属于 DOM,但你试图将其移动到属于 DOM 的节点内部,反之亦然。 - 指定的
movedNode
是正在调用moveBefore()
的 Element 的祖先。 - 你试图在两个不同的文档之间移动
movedNode
。 - 指定的
movedNode
不是Element
或CharacterData
节点。
- 指定的
NotFoundError
TypeError
-
指定的
referenceNode
不是你正在调用moveBefore()
的节点的子节点,即你试图将movedNode
移动到的节点。 TypeError
TypeError
-
未提供第二个参数。
描述
moveBefore()
方法将给定节点移动到 DOM 中的新位置。它提供了与 Node.insertBefore()
方法类似的功能,不同之处在于它不会先移除再重新插入节点。这意味着节点的状态(如果使用 insertBefore()
和类似机制移动节点,其状态会重置)在移动后会保留。这包括:
和
元素的播放状态不包含在上述列表中,因为这些元素在被移除和重新插入时会保留其状态,无论使用何种机制。
当使用 MutationObserver
观察 DOM 变化时,使用 moveBefore()
移动的节点将被记录为 已移除节点 和 已添加节点。
moveBefore()
约束
使用 moveBefore()
时需要注意一些约束:
- 它只能在同一个文档中移动节点时工作。
- 如果你尝试将未连接到 DOM 的节点移动到已连接的父节点中,或反之,它将不起作用。
在这种情况下,moveBefore()
将抛出 HierarchyRequestError
异常。如果上述约束是你的特定用例的要求,你应该改用 Node.insertBefore()
,或者使用 try...catch
来处理因此类情况引起的错误。
移动自定义元素并保留状态
每次自定义元素在 DOM 中的位置通过 Element.moveBefore()
或类似方法(如 Node.insertBefore()
)更新时,其 disconnectedCallback()
和 connectedCallback()
生命周期回调都会被触发。由于这些回调通常用于实现在元素生命周期开始或结束时运行的任何必需的初始化或清理代码,因此在移动元素(而不是移除或插入)时运行它们可能会导致其状态出现问题。
你可以使用 connectedMoveCallback()
回调来保留自定义元素的状态。当使用 moveBefore()
移动自定义元素时,将运行 connectedMoveCallback()
而不是 connectedCallback()
和 disconnectedCallback()
。
有关更多信息,请参阅移动自定义元素。
示例
moveBefore()
的基本用法
在此演示中,我们演示了 moveBefore()
的基本用法。
HTML
HTML 包含一个 我们为盒子的外观、感觉和间距提供了一些基本的样式,并使用 Flexbox 来居中其内容。 在我们的脚本中,我们通过 渲染后的示例如下所示: 尝试点击 在此演示中,我们提供了多种机制来移动包含 YouTube 嵌入的 HTML 包含一个 我们使用 Flexbox 进行布局,使两个 在我们的脚本中,我们通过 渲染后的示例如下所示: 尝试播放 YouTube 嵌入,然后点击每个 加载中… 元素,其中包含一个
元素。
,我们稍后将使用它来移动
<article id="wrapper">
<div id="mover">
<button>Move me!</button>
</div>
<section id="section1">
<h2>Section 1</h2>
</section>
<section id="section2">
<h2>Section 2</h2>
</section>
</article>
CSS
#section1,
#section2,
#mover {
width: 200px;
height: 80px;
border: 5px solid rgb(0 0 0 / 0.25);
margin-bottom: 10px;
display: flex;
align-items: center;
justify-content: center;
}
#section1,
#section2 {
background-color: hotpink;
}
#mover {
background-color: orange;
}
JavaScript
addEventListener()
为 附加了一个点击事件监听器。当按钮被点击时,我们检查
mover
nextElementSibling
是否是第一个 元素。如果是,我们对
wrapper
调用
moveBefore()
,并指定将 之前。如果不是,我们使用
moveBefore()
将 之前。
const wrapper = document.getElementById("wrapper");
const section1 = document.getElementById("section1");
const section2 = document.getElementById("section2");
const mover = document.getElementById("mover");
const moveBtn = document.querySelector("button");
moveBtn.addEventListener("click", () => {
if (mover.nextElementSibling === section1) {
wrapper.moveBefore(mover, section2);
} else {
wrapper.moveBefore(mover, section1);
}
});
结果
几次,注意它是如何在两个位置之间切换的。
演示状态保留
moveBefore()
如何保留嵌入的播放状态,而其他机制则不保留。
HTML
元素,其中包含两个
元素。第一个
元素包含一个
元素,我们稍后将添加功能,通过 JavaScript 在部分之间移动嵌入的
<article id="wrapper">
<section id="section1">
<div id="mover">
<iframe
width="300"
height="200"
src="https://www.youtube.com/embed/XvoENpR9cCQ?si=o2i6MvxugD-O5yyv"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen></iframe>
</div>
</section>
<section id="section2"></section>
</article>
<div id="controls">
<button id="move-before">move with <code>moveBefore()</code></button>
<button id="insertbefore">move with <code>insertBefore()</code></button>
<button id="prepend">move with <code>prepend()</code></button>
</div>
CSS
元素并排显示,并使按钮在
controls
#wrapper,
#controls {
width: 100%;
display: flex;
}
#wrapper {
margin-bottom: 10px;
}
section {
flex: 1;
padding: 10px;
}
#controls {
display: flex;
justify-content: space-around;
}
#section1 {
background-color: hotpink;
}
#section2 {
background-color: orange;
}
#mover {
max-width: 100%;
background-color: black;
}
JavaScript
addEventListener()
为每个 附加
click
事件监听器。当按钮被点击时,我们检查哪个 元素是我们的嵌入
parentElement
,然后使用相关函数(moveBefore()
、insertBefore()
或 prepend()
)将其移动到另一个 元素内部。
const section1 = document.getElementById("section1");
const section2 = document.getElementById("section2");
const mover = document.getElementById("mover");
const moveBeforeBtn = document.getElementById("move-before");
const insertbeforeBtn = document.getElementById("insertbefore");
const prependBtn = document.getElementById("prepend");
moveBeforeBtn.addEventListener("click", () => {
if (mover.parentElement === section1) {
section2.moveBefore(mover, null);
} else {
section1.moveBefore(mover, null);
}
});
insertbeforeBtn.addEventListener("click", () => {
if (mover.parentElement === section1) {
section2.insertBefore(mover, null);
} else {
section1.insertBefore(mover, null);
}
});
prependBtn.addEventListener("click", () => {
if (mover.parentElement === section1) {
section2.prepend(mover);
} else {
section1.prepend(mover);
}
});
结果
几次,以将
insertBefore()
和 prepend()
的情况下,嵌入状态在每次移动后都会重置,因此需要重新启动。然而,在使用 moveBefore()
的情况下,状态在每次移动后都会保留。
规范
规范
DOM
# dom-parentnode-movebefore浏览器兼容性
另见