我正在尝试重用这样的片段,但是事件监听器只工作一次,当片段被重用时不再存在:
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的行为令人费解。直觉告诉我,这种现象与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版本应该可以正常工作,就像这里的第一个代码片段可以正常工作一样。但事实并非如此。我听不懂。很好的问题!