【问题标题】:jQuery alternative for replacing html without breaking Event Listeners在不破坏事件侦听器的情况下替换 html 的 jQuery 替代方案
【发布时间】:2017-09-14 15:10:56
【问题描述】:

在我的代码的某个点,我需要从 AJAX 请求中提取一个 html 字符串并用它替换某个容器。

我有这个,但是,正如网络上的一些参考资料所述,它被垃圾收集并取消绑定事件侦听器

this.rightPanel.innerHTML = content;

但是,jQuery .html() 函数不会发生这种情况,它使事件侦听器保持工作,所以这样做

$(this.rightPanel).html(content);

工作无缺陷。

我不想使用 jQuery 进行 DOM 操作,即使浏览器本身支持它。我必须重现与 jQuery .html() 相同的行为的最佳选择是什么?

谢谢

【问题讨论】:

  • “但是,jQuery .html() 函数不会发生这种情况......” 是的,它会发生。 “...使事件侦听器保持工作...”不,它没有。
  • 我不想使用 jQuery 进行 DOM 操作,即使浏览器本身支持它。 JQuery 是 JavaScript。所有浏览器都支持它。
  • @ScottMarcus,我的意思是,我想使用原生 DOM 函数,比如 querySelector,而不是使用像 jQuery 这样的库。

标签: javascript jquery dom dom-manipulation


【解决方案1】:

但是,jQuery .html() 函数不会发生这种情况...

是的,确实如此。

...使事件侦听器保持工作...

不,它没有。 :-)

Like-for-like,它们对事件监听器做同样的事情:

// 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仅在冒泡期间通过元素时触发您的处理程序。这样,您可以替换后代元素,因为事件侦听器不在它们上,而是在容器/祖先上。

你也可以不使用 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">

【讨论】:

  • 如果我理解正确,您的意思是 jQuery 在更高层次的元素(如 body)上实现事件侦听器,并将事件委托给指定的选择器,可能是在 event.target 匹配它时?因此,您提供的函数类似于 jQuery 中的 .on() 函数,对吗?谢谢!
  • @JoãoDias: jQuery 可以做到这一点,如果你要求的话;除非你这样做,否则它不会。例如,这会将处理程序直接绑定到元素:$("#element").on("click", handler); 但是这会将处理程序绑定到document,同时仅在事件通过#element 元素时触发处理程序:$(document).on("click", "#element", handler); 是的,addDelegated 以上是你如何直接使用 DOM 而不是通过 jQuery 的辅助函数使用 DOM 来做同样事情的草图。
  • 我就是这么想的。但是,与许多地方一样,通过使用 jQuery 并且很少涉足核心 javascript,我无法完全理解其背后的真正含义。谢谢你说清楚;)
猜你喜欢
  • 2017-08-21
  • 2021-08-20
  • 2022-09-26
  • 2014-08-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多