javascript 交换两个 html 元素并在它们上保留事件侦听器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10716986/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 10:48:43  来源:igfitidea点击:

Swap two html elements and preserve event listeners on them

javascriptjquerydomdom-events

提问by Ext

There are similar questions, but all the answers are for swapping html elements only for the content inside.

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

I need to swap two divs, with lots of content in them (tables, select boxes, inputs, etc.). The elements have event listeners on them, so I need to preserve them after swapping the main divs.

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

I have access to jQuery 1.5. So answers with it are OK.

我可以访问 jQuery 1.5。所以用它回答是可以的。

回答by jfriend00

To swap two divs without losing event handlers or breaking DOM references, you can just move them in the DOM. The key is NOT to change the innerHTML because that recreates new DOM nodes from scratch and all prior event handlers on those DOM objects are lost.

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

But, if you just move the DOM elements to a new place in the DOM, all events stay attached because the DOM elements are only reparented without changing the DOM elements themselves.

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

Here's a quick function that would swap two elements in the DOM. It should work with any two elements as long as one is not a child of the other:

这是一个快速函数,可以交换 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);
}

You can see it work here: http://jsfiddle.net/jfriend00/NThjN/

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



And here's a version that works without the temporary element inserted:

这是一个无需插入临时元素即可工作的版本:

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);
        }
    }
}

Working demo: http://jsfiddle.net/jfriend00/oq92jqrb/

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

回答by Robert

This is a simpler function for swapping two elements without actually reloading the element...

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

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

Note: if the obj1 has an embedded video like YouTube, it will not reload when swapped. It's just the position of the elements that changed.

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

回答by kennebec

If you keep track of the two elements' parentNodes and the nextSibling of one, you can swap two elements with their children without any temporary placeholders.

如果您跟踪两个元素的 parentNode 和一个的 nextSibling,则可以在没有任何临时占位符的情况下交换两个元素与其子元素。

If the second element is an only child, or the last child of its parent, its replacement is (properly) appended to the parent.

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

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;
}

回答by Elias Van Ootegem

This somewhat depends on how your events are bound to the elements you're swapping. If you're using jQuery, then thisanswer is all you need, really.

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

The main thing is not to deleteor removeChildnodethe elements, and just copy-paste the html elsewhere. In doing so, some browsers will clear all resources (event handlers included) so, bound events will be lost. Though IE is notorious for leaking memory when it comes to dynamically bound events. It's hard to predict how various browsers will behave, really.

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

Basically, I'd say: swap elements in any way you like, except for copy/paste HTML strings, and bind your events using jQuery's .live()method. Since I don't think 1.5 has the .onmethod

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

回答by cronoklee

My simple function seems to be the shortest and most widely compatible. It doesn't need placeholders or reload elements or anything messy like that:

我这个简单的函数好像是最短的,兼容最广的。它不需要占位符或重新加载元素或任何类似的东西:

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);
}

回答by cssyphus

Since jQuery is tagged in the question, here is a jQuery solution:

由于问题中标记了 jQuery,因此这是一个 jQuery 解决方案:

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

That's it. jQuery will cut/paste it to the new location.

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



This could also be helpful:

这也可能有帮助:

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

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

回答by Alexander Chernosvitov

This all is very strange considering the fact that o1.swapNode(o2); works very well in IE for very long time. In my case of object and text nodes intermixed, works only one version (already shown here):

考虑到 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);

Yes, I hate creating temporary node, but the above version without this trick fails if you use it straight (without calling function). Sometimes you don't want to call a function.

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

回答by Andrew Gale

It's really easy if you're swapping elements next to each other:

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

<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)');

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