为什么事件监听器在重用片段时会消失?

问题描述 投票:1回答:1

我正在尝试重用这样的片段,但是事件监听器只工作一次,当片段被重用时不再存在:

https://codepen.io/dvtan/pen/dyyGVKm

let $home = $(`
<div>
  <h1>Home page</h1>
  <button class="btn btn-primary">Go to another page</button>
</div>`);
let $another = $(`
<div>
  <h1>Another page</h1>
  <button class="btn btn-primary">Go back</button>
</div>`);
$("body").html($home);
$home.find('.btn').on('click', () => {
  $("body").html($another);
});
$another.find('.btn').on('click', () => {
  $("body").html($home);
});

我认为直观上讲,事件侦听器应该遵循周围的片段,因此它们像这样消失就没有意义。为什么会发生,这有什么解决方案?

jquery event-listener jquery-events
1个回答
0
投票

请原谅我发布了没有答案的问题-我仔细研究了一下,发现jQuery的行为令人费解。直觉告诉我,这种现象与JavaScript does not copy event listeners when it clones a node有关。我坚信,对您问题的正确答案只不过是与上述旧有SO问题的链接。但事实并非如此。

首先,在当前情况下,克隆是完全不必要。我们的主页有一个片段(或dom树)(附加了事件处理程序),另一页面有另一个片段/ dom树。单击其中一个按钮时,我们需要进行任何克隆。我们只是通过相应的“其他” dom树交换页面的内容(即document.body的唯一子元素)。

我重写了您的代码段,使得在香草javascript的帮助下,如上所述发生了“交换”。它的行为方式如下:[[一个人应该认为 jQuery版本的行为:有效。

let $home = $(` <div> <h1>Home page</h1> <button class="btn btn-primary">Go to another page</button> </div>`); let $another = $(` <div> <h1>Another page</h1> <button class="btn btn-primary">Go back</button> </div>`); var home0, another0; function drainBody(){ while (document.body.lastChild){ document.body.removeChild(document.body.lastChild); } } function setBody(domElt){ drainBody(); document.body.appendChild(domElt); } $home.find('.btn').on('click', () => { setBody(another0); }); home0 = $home[0]; $another.find('.btn').on('click', () => { setBody(home0); }); another0 = $another[0]; setBody(home0);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
[发现这一点后,我坚信jQuery执行了一些不必要的克隆,根据上述古老的SO问题,它将解释一切:事件处理程序将因克隆而消失。 

但是令我惊讶的是,这种解释似乎是错误的。它确实是dom节点,而不是克隆节点;但事件处理程序仍然消失了。确实非常非常奇怪。这是一个片段,显示“转到另一页”按钮的dom节点已更改

not

(等于===)

let $home = $(` <div> <h1>Home page</h1> <button class="btn btn-primary">Go to another page</button> <pre id='console'></pre> </div>`); let $another = $(` <div> <h1>Another page</h1> <button class="btn btn-primary">Go back</button> </div>`); $("body").html($home); $home.find('.btn').on('click', () => { $("body").html($another); }); $another.find('.btn').on('click', () => { $("body").html($home); var reincarnatedGoButton = document.body.children[0].children[1]; document.getElementById('console').textContent = [ goOtherBtn.textContent, reincarnatedGoButton.textContent, goOtherBtn === reincarnatedGoButton ].join(' &&& ') }); var goOtherBtn = document.body.children[0].children[1]
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
问题下的评论极具误导性。您没有放入新的HTML字符串。 $(...)(基本上)是dom节点(长度为1)的数组,因此,本质上是dom节点-而不是字符串。不过,如果该dom节点将是“新副本”,它将说明问题,因此这些注释也不会完全消失。但是正如我所展示的,它
不是
是一个新副本。因此,我

尚未

回答了您的问题。我不能我至少和你一样困惑。假设dom节点相同,那么jQuery版本应该可以正常工作,就像这里的第一个代码片段可以正常工作一样。但事实并非如此。我听不懂。
很好的问题!
© www.soinside.com 2019 - 2024. All rights reserved.