如果我有以下html:
<html>
<div id="main_content">
<button>click me</button>
<script src="main.js" ></script>
</div>
</html>
和main.js:
$('#main_content').on('click', 'button', function() {
console.log('you clicked');
});
如果我执行整页加载,则单击该按钮仅注册一个控制台消息。但是,如果我随后通过AJAX请求重新加载main_content's
内容,则每次单击按钮都会发出2条控制台消息。它将为每个后续的AJAX加载提供3,4,5 ...消息,但总是一个用于整页重新加载。
有人可以解释这种行为并建议可能的解决方案吗?
答案 0 :(得分:5)
那是因为你正在加载main.js的多个副本,因此每次都要附加一个事件处理程序。
每次加载<script>
时,都会附加一个处理程序
<button>click me</button>
<script src="main.js" ></script>
这里的教训是解析了由ajax加载的脚本,因此如果你在其中有处理程序,则会附加它们
答案 1 :(得分:3)
如果您确实需要一直重新加载该脚本,请在其中执行此操作:
$('#main_content').off("click").on('click', 'button', function() {
console.log('you clicked');
});
否则显然将它放在其他地方。
答案 2 :(得分:1)
我认为您将该脚本放入重新加载的内容中,而不是放在所有脚本通常驻留的head部分中,因为事件处理程序每次重新加载时都会与#main_content
分离?嗯,还有另一种方式:
$(function(){
...
$('body').on('click', '#main_content', function() { console.log('You clicked!'); });
});
您可以只放置,加载和执行此代码一次 - 并且每次重新加载有问题的块时都不需要重新附加事件。
请注意,我的代码中的body
最好用更具体的元素替换 - 在完美的世界中,#main_content
元素的直接父级。
更新:这就是所谓的事件委托,它在.on docpage中得到了很好的描述。在以前版本的jQuery中,您必须使用.live
或.delegate
方法。
答案 3 :(得分:1)
正如已经说过的那样,每次执行.load()
时,main.js都会被重新分析并重新运行。
您有几种方法可以解决这个问题:
.load()
时都不会对其进行重新分析和运行。这些是为了简化实施而提出的。
对于选项2,您可以将所有main.js放在这样的if
语句中,以便它只执行一次:
if (!window.__main__js__defined) {
window.__main__js__defined = true;
// rest of main.js code here
}
对于选项3,您必须使用每个对象上的.data()
来保护您希望反重复保护的每个单独的事件处理程序,以设置您已经安装了给定事件处理程序的标志