交换两个 html 元素并保留其上的事件侦听器
Swap two html elements and preserve event listeners on them
类似的问题,但所有的答案都是为了交换html元素,只换取里面的内容。
我需要交换两个div,其中包含大量内容(表格,选择框,输入等)。这些元素上有事件侦听器,所以我需要在交换主div 后保留它们。
我可以访问jQuery 1.5。所以答案是可以的。
要在不丢失事件处理程序或破坏 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/
这是一个更简单的函数,用于交换两个元素而无需实际重新加载元素......
function swapElements(obj1, obj2) {
obj2.nextSibling === obj1
? obj1.parentNode.insertBefore(obj2, obj1.nextSibling)
: obj1.parentNode.insertBefore(obj2, obj1);
}
注意:如果 obj1 有像 YouTube 这样的嵌入式视频,则在交换时不会重新加载。这只是元素的位置发生了变化。
如果跟踪两个元素的父节点和一个元素的下一个同级节点,则可以在没有任何临时占位符的情况下将两个元素与其子元素交换。
如果第二个元素是独生子元素或其父元素的最后一个子元素,则其替换将(正确)追加到父元素。
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;
}
我的简单函数似乎是最短和最广泛兼容的。它不需要占位符或重新加载元素或任何类似的东西:
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);
}
这在一定程度上取决于您的事件如何绑定到您要交换的元素。如果你使用的是jQuery,那么这个答案就是你所需要的,真的。
最主要的是不要delete
或removeChildnode
元素,而只是将html复制粘贴到其他地方。这样做时,某些浏览器将清除所有资源(包括事件处理程序),因此绑定事件将丢失。尽管IE在动态绑定事件方面因泄漏内存而臭名昭著。真的很难预测各种浏览器的行为。
基本上,我会说:以任何你喜欢的方式交换元素,除了复制/粘贴HTML字符串,并使用jQuery的.live()
方法绑定你的事件。由于我认为 1.5 没有.on
方法
由于 jQuery 在问题中被标记,这里有一个 jQuery 解决方案:
$('#el_to_move').appendTo('#target_parent_el');
jQuery会将其剪切/粘贴到新位置。
这也可能会有所帮助:
https://api.jquery.com/detach/
考虑到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);
是的,我讨厌创建临时节点,但是如果您直接使用它(不调用函数),则没有此技巧的上述版本会失败。有时你不想调用函数。
如果你把元素并排交换,这真的很容易:
<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)');
Internet Explorer 已死
所有现代浏览器都具有:
-
https://developer.mozilla.org/en-US/docs/Web/API/Element/before
-
https://developer.mozilla.org/en-US/docs/Web/API/Element/after
function swapDOMElements( el1 , el2, temp=el2.previousElementSibling){
el1.after(e2);
temp.after(el1);
}
- Highslide(iframe的侦听器)
- 如何在for循环中添加事件侦听器
- 选项卡侦听器未被来自后台脚本的消息激活
- 未命中服务器发送的事件侦听器
- 如何覆盖原型中的事件侦听器
- 加载侦听器上的函数触发得太早
- 无法将事件侦听器附加到画布
- 如何在d3.js中自定义事件侦听器
- 在es6中,将带有回调的事件侦听器设置为可迭代的
- 事件侦听器未在chrome扩展中的options.js中启动
- IE8更改文本区域上的事件侦听器不工作
- 将事件侦听器添加到文档,而不是签入元素存在,然后添加事件侦听器
- jQuery将侦听器的大小调整为只触发宽度的变化
- javascript删除事件侦听器
- 我应该/如何清除mousemove JQuery事件侦听器
- 在JQuery中使用谷歌地图Api事件/侦听器
- 如何在侦听器之后添加可拖动功能
- 如果侦听器附加到父元素,是否可以区分单击发生在哪个子元素上
- 交换两个 html 元素并保留其上的事件侦听器
- 如何在排序后保留事件侦听器