如何在 JavaScript 中交换 DOM 子节点?
Posted
技术标签:
【中文标题】如何在 JavaScript 中交换 DOM 子节点?【英文标题】:How to swap DOM child nodes in JavaScript? 【发布时间】:2012-04-01 17:19:50 【问题描述】:交换子节点顺序的最简单方法是什么?
例如,我希望 childNode[3] 成为 childNode[4],反之亦然。
【问题讨论】:
【参考方案1】:无需克隆。您可以将一个节点移到另一个节点之前。 .insertBefore()
方法会将其从当前位置取出并插入到其他位置(从而移动它):
childNode[4].parentNode.insertBefore(childNode[4], childNode[3]);
你得到了节点的父节点。然后在父节点上调用 insertBefore 方法,并将 childNode[4] 节点传递给它,并告诉它您希望它在 childNode[3] 之前插入。这将为您提供交换订单的结果,因此完成后 4 将在 3 之前。
参考documentation on insertBefore。
任何插入到 DOM 中的节点都会先自动移除,然后再插入回来,因此无需先手动移除。
【讨论】:
+1 我将其总结为“一个节点一次只能存在于 DOM 中的一个位置”:因此将其插入其他位置会将其从当前位置移动。 如何为未知节点 id 实现相同的目标?说不知道有没有childNode[3] @armen - 你必须有一些方法来获取你想要交换的两个元素。几乎总有一种方法可以做到这一点,但具体如何取决于特定的 html 情况和结构。 仅适用于相邻的兄弟姐妹,这不是问题。 @brannigan - 如果您想通用地交换任何两个元素,您可以在此处查看该代码:Swap two HTML elements。【参考方案2】:使用.before
或.after
!
这是原版 JS!
childNode[3].before(childNode[4]);
或
childNode[4].after(childNode[3]);
要获得更多持久性交换,请尝试:
function swap(node1, node2)
const afterNode2 = node2.nextElementSibling;
const parent = node2.parentNode;
node1.replaceWith(node2);
parent.insertBefore(node1, afterNode2);
这应该可以工作,即使父母不匹配
Can I Use - 21 年 7 月 95%
【讨论】:
当 node1 恰好是 node2 的后继者时,该交换函数需要一个特殊情况:if (node1 === afterNode2) parent.insertBefore(node1, node2); else ...
参见jsfiddle.net/cayhorstmann/c9uqme45【参考方案3】:
jfriend00 的回答并没有真正交换元素(它仅“交换”彼此相邻且仅在同一父节点下的元素)。没关系,因为这是问题。
此示例通过克隆来交换元素,但不考虑它们的位置和 DOM 级别:
// Note: Cloned copy of element1 will be returned to get a new reference back
function exchangeElements(element1, element2)
var clonedElement1 = element1.cloneNode(true);
var clonedElement2 = element2.cloneNode(true);
element2.parentNode.replaceChild(clonedElement1, element2);
element1.parentNode.replaceChild(clonedElement2, element1);
return clonedElement1;
编辑:添加了新引用的返回(如果您想保留引用,例如访问属性“parentNode”(否则它会丢失))。示例:e1 = exchangeElements(e1, e2);
【讨论】:
这将丢失分配给节点的所有事件处理程序。【参考方案4】:我需要一个函数来交换两个任意节点,将交换的元素保持在 dom 中的相同位置。例如,如果 a 相对于其父级位于位置 2,而 b 相对于其父级位于位置 0,则 b 应替换位置 2 a 的前父母和 a 的孩子应该替换 b 的前父母的孩子 0。
这是我的解决方案,它允许交换位于 dom 的完全不同的部分。请注意,交换不能是简单的三步交换。这两个元素中的每一个都需要首先从 dom 中删除,因为它们可能有需要更新的兄弟姐妹等。
解决方案:我放入了两个持有者 div 来保存每个节点的位置,以保持相对的兄弟顺序。然后我将每个节点重新插入到另一个占位符中,保持交换节点在交换之前的相对位置。 (我的解决方案类似于巴克的)。
function swapDom(a,b)
var aParent = a.parentNode;
var bParent = b.parentNode;
var aHolder = document.createElement("div");
var bHolder = document.createElement("div");
aParent.replaceChild(aHolder,a);
bParent.replaceChild(bHolder,b);
aParent.replaceChild(b,aHolder);
bParent.replaceChild(a,bHolder);
【讨论】:
【参考方案5】:对于没有cloneNode的任何节点的真正Swap:
<div id="d1">D1</div>
<div id="d2">D2</div>
<div id="d3">D3</div>
带 SwapNode 功能(使用 PrototypeJS):
function SwapNode(N1, N2)
N1 = $(N1);
N2 = $(N2);
if (N1 && N2)
var P1 = N1.parentNode;
var T1 = document.createElement("span");
P1.insertBefore(T1, N1);
var P2 = N2.parentNode;
var T2 = document.createElement("span");
P2.insertBefore(T2, N2);
P1.insertBefore(N2, T1);
P2.insertBefore(N1, T2);
P1.removeChild(T1);
P2.removeChild(T2);
SwapNode('d1', 'd2');
SwapNode('d2', 'd3');
将产生:
<div id="d3">D3</div>
<div id="d1">D1</div>
<div id="d2">D2</div>
【讨论】:
【参考方案6】:试试这个方法:
Get the parent element
存储two elements you want to swap
存储.nextSibling of the node that is last in order
例如:[1,2,3,4] => 我们要交换 3 和 2,然后存储 3 的 nextSibling,'4'。
.insertBefore(3,2);
.insertBefore(2,nextSibling);【讨论】:
【参考方案7】:代码说明
val & val2 是要交换的 2 个节点/元素 equiv(index) 在作为参数传递的索引处获取 DOM 中的当前节点/元素注意:它会计算评论和文本元素,所以要小心 xD
希望这会有所帮助:)
function equiv(index)
return Array.prototype.slice.call( document.querySelectorAll("*"))[index];
function swap (val,val2)
let _key = val.key;
let _key_ = val2.key;
_key_ = _key < _key_ ? _key_+1:_key_;
let _parent_ = val2.parentElement.valueOf();
if (val.parentElement.children.length ==1)
val.parentElement.appendChild(val2);
else
val.parentElement.insertBefore(val2,val);
if (_parent_.children.length ==0)
_parent_.appendChild(val);
else
let _sibling_ = equiv(_key_);
_parent_.insertBefore(val,_sibling_);
【讨论】:
【参考方案8】:考虑到要交换的两个元素的索引,无需克隆即可工作的解决方案:
function swapChildren(parentElement, index1, index2)
if (index1 === index2)
return
if (index1 > index2)
const temp = index1
index1 = index2
index2 = temp
const [index1]: element1, [index2]: element2 = parentElement.childNodes
if (index2 === index1 + 1)
parentElement.insertBefore(element2, element1)
else
const reference = element2.nextSibling
parentElement.replaceChild(element2, element1)
parentElement.insertBefore(element1, reference)
【讨论】:
【参考方案9】:使用虚拟兄弟作为临时位置标记,然后使用.before
(或.after
)。
它适用于任何兄弟姐妹(不仅是相邻的),并且还维护事件处理程序。
function swap(a, b)
let dummy = document.createElement("span")
a.before(dummy)
b.before(a)
dummy.replaceWith(b)
<div id="div1">A</div>
<div id="div2">B</div>
<p> parent<div id="div3">C</div>
</p>
<button onclick="swap(div1, div3)">swap</button>
就像临时变量用于交换变量一样,如果缺少更复杂的方法。
【讨论】:
以上是关于如何在 JavaScript 中交换 DOM 子节点?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 DOM(javascript 或 jquery)中显示元素的值?