如何在动态加载的脚本中使用jQuery on()

时间:2012-06-20 21:46:58

标签: javascript jquery ajax jquery-on

如果我有以下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 ...消息,但总是一个用于整页重新加载。

有人可以解释这种行为并建议可能的解决方案吗?

4 个答案:

答案 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都会被重新分析并重新运行。

您有几种方法可以解决这个问题:

  1. 将main.js移到动态加载的内容之外,以便每次执行.load()时都不会对其进行重新分析和运行。
  2. 修改main.js,使整个脚本只执行一次。
  3. 修改main.js以了解多次加载,以防止重复安装相同的事件处理程序。
  4. 这些是为了简化实施而提出的。

    对于选项2,您可以将所有main.js放在这样的if语句中,以便它只执行一次:

    if (!window.__main__js__defined) {
        window.__main__js__defined = true;
    
       // rest of main.js code here
    
    }
    

    对于选项3,您必须使用每个对象上的.data()来保护您希望反重复保护的每个单独的事件处理程序,以设置您已经安装了给定事件处理程序的标志