jQuery 替换 html 而不破坏事件侦听器的替代方案
jQuery alternative for replacing html without breaking Event Listeners
在我的代码的某个点,我需要从 AJAX 请求中获取一个 html 字符串并用它替换某个容器。
我有这个,但是,正如网络上的几个参考资料所述,它被垃圾收集并取消绑定事件侦听器
this.rightPanel.innerHTML = content;
然而,这不会发生在 jQuery .html()
函数中,它使事件侦听器保持工作状态,所以
$(this.rightPanel).html(content);
完美无瑕。
我不想使用 jQuery 进行 DOM 操作,即使浏览器本身支持它也是如此。我必须重现与 jQuery .html()
相同的行为的最佳选择是什么?
谢谢
This however, doesn't happen with jQuery .html() function...
是的,确实如此。
...which keeps the event listeners working...
不,不是。 :-)
类似地,他们对事件侦听器做同样的事情:
// DOM
document.getElementById("btn1").addEventListener("click", function() {
console.log("Button 1");
});
// jQuery
$("#btn2").on("click", function() {
console.log("Button 2");
});
// Replace 'em
$("#btnRep").on("click", function() {
var wrap1 = document.getElementById("wrap1");
wrap1.innerHTML = wrap1.innerHTML + " (replaced)";
var wrap2 = $("#wrap2");
wrap2.html(wrap2.html() + " (replaced)");
});
<p>Click Button 1, then Button 2, Then Replace, then Buttons 1 and 2 again -- you'll see *neither* of them has a handler anymore after being replaced.</p>
<div id="wrap1">
<input type="button" id="btn1" value="Button 1">
</div>
<div id="wrap2">
<input type="button" id="btn2" value="Button 2">
</div>
<input type="button" id="btnRep" value="Replace">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
您可能已经看到 jQuery 使 事件委托 真的非常简单:这就是您实际将事件挂接到祖先元素的地方(甚至可能body
),但是你要求 jQuery 只在它在冒泡期间通过元素时触发你的处理程序。这样,您可以替换后代元素,因为事件侦听器不在它们上,它在 container/ancestor.
上
你也可以在没有 jQuery 的情况下做到这一点,只是需要多做一些工作:
function addDelegated(element, eventName, selector, handler) {
element.addEventListener(eventName, function(e) {
// Start with the target element, and go through its parents
// until we reach the element we hooked the event on (`this`)
var element = e.target;
while (element && element !== this) {
// `matches` test the element against a CSS selector
if (element.matches(selector)) {
// Yes, trigger the handler
return handler.call(element, e);
}
element = element.parentNode;
}
});
}
// Hook the event on wrap1
addDelegated(document.getElementById("wrap1"), "click", "#btn1", function() {
console.log("Button 1");
});
// Replace
document.getElementById("btnRep").addEventListener("click", function() {
var wrap1 = document.getElementById("wrap1");
wrap1.innerHTML = wrap1.innerHTML + " (replaced)";
});
<p>Click Button 1, then Replace, then Button 1 again.</p>
<div id="wrap1">
<input type="button" id="btn1" value="Button 1">
</div>
<input type="button" id="btnRep" value="Replace">
在我的代码的某个点,我需要从 AJAX 请求中获取一个 html 字符串并用它替换某个容器。
我有这个,但是,正如网络上的几个参考资料所述,它被垃圾收集并取消绑定事件侦听器
this.rightPanel.innerHTML = content;
然而,这不会发生在 jQuery .html()
函数中,它使事件侦听器保持工作状态,所以
$(this.rightPanel).html(content);
完美无瑕。
我不想使用 jQuery 进行 DOM 操作,即使浏览器本身支持它也是如此。我必须重现与 jQuery .html()
相同的行为的最佳选择是什么?
谢谢
This however, doesn't happen with jQuery .html() function...
是的,确实如此。
...which keeps the event listeners working...
不,不是。 :-)
类似地,他们对事件侦听器做同样的事情:
// DOM
document.getElementById("btn1").addEventListener("click", function() {
console.log("Button 1");
});
// jQuery
$("#btn2").on("click", function() {
console.log("Button 2");
});
// Replace 'em
$("#btnRep").on("click", function() {
var wrap1 = document.getElementById("wrap1");
wrap1.innerHTML = wrap1.innerHTML + " (replaced)";
var wrap2 = $("#wrap2");
wrap2.html(wrap2.html() + " (replaced)");
});
<p>Click Button 1, then Button 2, Then Replace, then Buttons 1 and 2 again -- you'll see *neither* of them has a handler anymore after being replaced.</p>
<div id="wrap1">
<input type="button" id="btn1" value="Button 1">
</div>
<div id="wrap2">
<input type="button" id="btn2" value="Button 2">
</div>
<input type="button" id="btnRep" value="Replace">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
您可能已经看到 jQuery 使 事件委托 真的非常简单:这就是您实际将事件挂接到祖先元素的地方(甚至可能body
),但是你要求 jQuery 只在它在冒泡期间通过元素时触发你的处理程序。这样,您可以替换后代元素,因为事件侦听器不在它们上,它在 container/ancestor.
你也可以在没有 jQuery 的情况下做到这一点,只是需要多做一些工作:
function addDelegated(element, eventName, selector, handler) {
element.addEventListener(eventName, function(e) {
// Start with the target element, and go through its parents
// until we reach the element we hooked the event on (`this`)
var element = e.target;
while (element && element !== this) {
// `matches` test the element against a CSS selector
if (element.matches(selector)) {
// Yes, trigger the handler
return handler.call(element, e);
}
element = element.parentNode;
}
});
}
// Hook the event on wrap1
addDelegated(document.getElementById("wrap1"), "click", "#btn1", function() {
console.log("Button 1");
});
// Replace
document.getElementById("btnRep").addEventListener("click", function() {
var wrap1 = document.getElementById("wrap1");
wrap1.innerHTML = wrap1.innerHTML + " (replaced)";
});
<p>Click Button 1, then Replace, then Button 1 again.</p>
<div id="wrap1">
<input type="button" id="btn1" value="Button 1">
</div>
<input type="button" id="btnRep" value="Replace">