31

有类似的问题,但所有的答案都是为了只为里面的内容交换 html 元素。

我需要交换两个 div,其中包含很多内容(表格、选择框、输入等)。元素上有事件监听器,所以我需要在交换主 div 后保留它们。

我可以访问 jQuery 1.5。所以答案是可以的。

4

8 回答 8

69

要在不丢失事件处理程序或破坏 DOM 引用的情况下交换两个 div,只需在 DOM 中移动它们即可。关键是不要更改 innerHTML,因为这会从头开始重新创建新的 DOM 节点,并且这些 DOM 对象上的所有先前事件处理程序都将丢失。

但是,如果您只是将 DOM 元素移动到 DOM 中的新位置,则所有事件都将保持关联,因为 DOM 元素只会重新设置父级,而不会更改 DOM 元素本身。

这是一个快速函数,可以交换 DOM 中的两个元素。只要一个元素不是另一个元素的子元素,它就可以与任意两个元素一起使用:

function swapElements(obj1, obj2) {
    // create marker element and insert it where obj1 is
    var temp = document.createElement("div");
    obj1.parentNode.insertBefore(temp, obj1);

    // move obj1 to right before obj2
    obj2.parentNode.insertBefore(obj1, obj2);

    // move obj2 to right before where obj1 used to be
    temp.parentNode.insertBefore(obj2, temp);

    // remove temporary marker node
    temp.parentNode.removeChild(temp);
}

你可以在这里看到它的工作原理:http: //jsfiddle.net/jfriend00/NThjN/


这是一个在没有插入临时元素的情况下工作的版本:

function swapElements(obj1, obj2) {
    // save the location of obj2
    var parent2 = obj2.parentNode;
    var next2 = obj2.nextSibling;
    // special case for obj1 is the next sibling of obj2
    if (next2 === obj1) {
        // just put obj1 before obj2
        parent2.insertBefore(obj1, obj2);
    } else {
        // insert obj2 right before obj1
        obj1.parentNode.insertBefore(obj2, obj1);

        // now insert obj1 where obj2 was
        if (next2) {
            // if there was an element after obj2, then insert obj1 right before that
            parent2.insertBefore(obj1, next2);
        } else {
            // otherwise, just append as last child
            parent2.appendChild(obj1);
        }
    }
}

工作演示:http: //jsfiddle.net/jfriend00/oq92jqrb/

于 2012-05-23T09:48:02.940 回答
8

这是一个更简单的功能,用于交换两个元素而无需实际重新加载元素......

function swapElements(obj1, obj2) {
    obj2.nextSibling === obj1
    ? obj1.parentNode.insertBefore(obj2, obj1.nextSibling)
    : obj1.parentNode.insertBefore(obj2, obj1); 
}

注意:如果 obj1 有像 YouTube 这样的嵌入视频,则在交换时不会重新加载。只是元素的位置发生了变化。

于 2013-08-30T10:49:35.333 回答
1

如果您跟踪两个元素的 parentNodes 和一个的 nextSibling,您可以将两个元素与其子元素交换,而无需任何临时占位符。

如果第二个元素是唯一的子元素,或者是其父元素的最后一个子元素,则其替换(正确)附加到父元素。

function swap(a, b){
    var p1= a.parentNode, p2= b.parentNode, sib= b.nextSibling;
    if(sib=== a) sib= sib.nextSibling;
    p1.replaceChild(b, a);
    if(sib) p2.insertBefore(a, sib);
    else p2.appendChild(a);
    return true;
}
于 2012-05-23T13:54:37.800 回答
1

我的简单功能似乎是最短和最广泛兼容的。它不需要占位符或重新加载元素或任何类似的混乱:

function swapElements(el1, el2) {
    var p2 = el2.parentNode, n2 = el2.nextSibling
    if (n2 === el1) return p2.insertBefore(el1, el2)
    el1.parentNode.insertBefore(el2, el1);
    p2.insertBefore(el1, n2);
}
于 2016-09-06T11:19:18.140 回答
0

这在某种程度上取决于您的事件如何绑定到您正在交换的元素。如果您使用的是 jQuery,那么这个答案就是您所需要的,真的。

最主要的不是元素deleteremoveChildnode而是将html复制粘贴到其他地方。这样做时,某些浏览器会清除所有资源(包括事件处理程序),因此绑定的事件将丢失。尽管 IE 在动态绑定事件方面因泄漏内存而臭名昭著。真的很难预测各种浏览器的行为方式。

基本上,我会说:以任何你喜欢的方式交换元素,除了复制/粘贴 HTML 字符串,并使用 jQuery 的.live()方法绑定你的事件。因为我不认为 1.5 有.on方法

于 2012-05-23T09:41:15.437 回答
0

由于 jQuery 在问题中被标记,这里是一个 jQuery 解决方案:

  $('#el_to_move').appendTo('#target_parent_el');

而已。jQuery 会将其剪切/粘贴到新位置。


这也可能会有所帮助:

https://api.jquery.com/detach/

于 2016-11-26T16:51:35.830 回答
0

考虑到 o1.swapNode(o2); 的事实,这一切都非常奇怪。在 IE 中运行良好很长时间。在我的对象和文本节点混合的情况下,仅适用于一个版本(已在此处显示):

let t = document.createElement("div");
o1.parentNode.insertBefore(t, o1);
o2.parentNode.insertBefore(o1, o2);
t.parentNode.insertBefore(o2, t);
t.parentNode.removeChild(t);

是的,我讨厌创建临时节点,但是如果你直接使用它(没有调用函数),没有这个技巧的上述版本会失败。有时您不想调用函数。

于 2019-04-14T10:26:45.377 回答
0

如果您要交换彼此相邻的元素,这真的很容易:

<div class="container">
   <div class="item">Item 1</div>
   <div class="item">Item 2</div>
</div>

$('.container .item:nth-child(2)').insertBefore('.container .item:nth-child(1)');

于 2019-06-24T21:47:21.077 回答