如何使用jQuery将事件附加到动态HTML元素?

629

假设我有一些jQuery代码,将事件处理程序附加到所有类名为.myclass的元素。

例如:

$(function(){
    $(".myclass").click( function() {
        // do something
    });
});

我的HTML可能如下所示:

<a class="myclass" href="#">test1</a>
<a class="myclass" href="#">test2</a>
<a class="myclass" href="#">test3</a>

那个方法可以完美运行。 但是,请考虑如果.myclass元素在将来的某个时刻写入页面。

例如:

<a id="anchor1" href="#">create link dynamically</a>
<script type="text/javascript">
$(function(){
    $("#anchor1").click( function() {
        $("#anchor1").append('<a class="myclass" href="#">test4</a>');
    });
});
</script>
在这种情况下,当用户单击时,将创建test4链接。
尽管test4带有class="myclass"类,但它没有关联click()处理程序。
基本上,我想编写一次click()处理程序,并使其适用于页面加载时存在的内容以及通过AJAX / DHTML后来带入的内容。 有什么办法可以解决这个问题?

1
这是一篇关于如何为动态元素绑定点击事件的详细文章 http://goo.gl/zlEbnv - Satinder singh
一个纯JavaScript(vanilla js)的解决方案:https://dev59.com/nHVC5IYBdhLWcg3wtzqs#27373951 - Ram Patra
这里是答案 https://www.youtube.com/watch?v=unk-U_LQWuA - Prem
也许这篇文章会有所帮助:https://dontrepeatyourself.org/post/django-todo-app-with-ajax-and-jquery/#update-a-todo - Yacine Rouizi
8个回答

1063

我添加了一个新的答案以反映后来jQuery版本的更改。从jQuery 1.7开始,.live()方法已被弃用。

根据http://api.jquery.com/live/

从jQuery 1.7开始,.live()方法已被弃用。使用.on()方法来附加事件处理程序。使用旧版jQuery的用户应首选使用.delegate()而不是.live()。

对于jQuery 1.7及以上版本,您可以使用.on()方法将事件处理程序附加到父元素,并将选择器与'myclass'组合作为参数传递。

请参阅http://api.jquery.com/on/

因此,不再需要使用...

$(".myclass").click( function() {
    // do something
});

你可以编写一个带有自定义属性的 HTML 元素,例如 <div data-myattribute="somevalue">。然后用 JavaScript 来选择该元素并访问其属性,例如 element.dataset.myattribute

$('body').on('click', 'a.myclass', function() {
    // do something
});

这将适用于所有在body中带有“myclass”的a标签,无论是已经存在还是后来动态添加的。

这里使用body标签作为示例,因为该标签没有更靠近的静态包围标签,但是在.on方法调用发生时存在的任何父级标签都可以使用。例如,对于将动态元素添加的列表的ul标签,将如下所示:

$('ul').on('click', 'li', function() {
    alert( $(this).text() );
});
只要存在ul标签,这段代码就会起作用(无需存在li元素)。

这个本来很棒的解决方案似乎在Fancybox中存在HTML内容的问题。我已经回归手动创建处理程序了。我还没有尝试iFrame内容,所以fanyxbos的内容是正文的一部分,或者在我的情况下是文档变量的一部分。 - user673046
7
live()已经被废弃,使用.on()代替。但是当我写$('selector').on('event', callback(){})时,不清楚为什么不起作用。需要在on()中写入所需的选择器。例如:$(document).on('event', 'selector', callback(){})或者$('body').on('event', 'selector', callback(){}) - Satya Prakash
4
性能方面呢?与直接附加事件相同吗? - chesscov77
在我的情况下,它会将事件分配给父标签。我使用的是jQuery版本1.12.4。有什么想法吗? - Yusril Maulidan Raji
@Sean和Chuck,感谢你们的回答和编辑。 :) - Vibhav Chaddha
显示剩余5条评论

121

有时仅仅做(得票最高的答案)并不总是足够的:

$('body').on('click', 'a.myclass', function() {
    // do something
});

这可能是一个问题,因为事件处理程序的执行顺序。如果您发现自己这样做,但由于处理的顺序而导致出现问题... 您可以将其包装到一个函数中,当调用该函数时“刷新”监听器。

例如:

function RefreshSomeEventListener() {
    // Remove handler from existing elements
    $("#wrapper .specific-selector").off(); 

    // Re-add event handler for all matching elements
    $("#wrapper .specific-selector").on("click", function() {
        // Handle event.
    }
}

因为它是一个函数,所以每次我按照这种方式设置我的监听器时,我通常会在文档准备就绪时调用它:

$(document).ready(function() {
    // Other ready commands / code

    // Call our function to setup initial listening
    RefreshSomeEventListener();
});

然后,每当您添加一些动态添加的元素时,请再次调用该方法:

function SomeMethodThatAddsElement() {
    // Some code / AJAX / whatever.. Adding element dynamically

    // Refresh our listener, so the new element is taken into account
    RefreshSomeEventListener();
}
希望这能有所帮助! 敬礼,

谢谢!其他答案都没能解决我的问题,但是你的方案完美解决了。不过,如果我在添加动态元素后调用RefreshSomeEventListener(),我的事件会触发两次。 - DKMudrechenko
2
很可能是因为您没有完全将事件侦听器从中删除。 - Ryan Steffer
这个有效,而且解释得很好。 - John Ruiz
这就是我一直在寻找的答案! - Dragos Vana

36

在 jQuery 1.7 之后,首选的方法是 .on().off()

Sean 的回答 提供了一个示例。

现已弃用:

请使用 jQuery 函数 .live().die()。适用于 jQuery 1.3.x。

从文档中可以看到:

要在单击每个段落时在警告框中显示其文本:

$("p").live("click", function(){
  alert( $(this).text() );
});

此外,livequery插件可以实现此功能,并支持更多事件。


如果我的选择器需要成为其他元素的父级,怎么办?例如: $("p").parent(".myclass").live("click", ... 这似乎无法与live()一起使用。 - frankadelic
你可以尝试将这个功能整合到一个查询中,像这样:$("p:has(.myclass)").live("click",...)。注意:有些情况下,live方法并不适用于所有事件。如果需要额外的支持,请查看livequery插件。 - Matt Brunell
1
这不再是正确的答案。自jQuery 1.7起,.live()方法已被弃用。请改用.on()。让我们给正确的答案[https://dev59.com/cHM_5IYBdhLWcg3wfTI0#9331127]一些赞。或者@Matt - 你想更新你的答案吗? - Zach Lysobey

6
如果您要向DOM添加大量锚点,请考虑使用事件委托。以下是一个简单的示例:
$('#somecontainer').click(function(e) {   
  var $target = $(e.target);   
  if ($target.hasClass("myclass")) {
    // do something
  }
});

5
您可以为页面上所有元素绑定单击事件,无论它们是已经存在于该页面还是将来某个时候到达,如下所示:

$(document).bind('click', function (e) {
   var target = $(e.target);
   if (target.is('.myclass')) {
      e.preventDefault(); // if you want to cancel the event flow
      // do something
   } else if (target.is('.myotherclass')) {
      e.preventDefault();
      // do something else
   }
});

我已经使用它一段时间了,效果很好。

在jQuery 1.7及更高版本中,建议使用.on()代替绑定或任何其他事件委托方法,但.bind()仍然有效。


3
将处理程序绑定到所有当前和未来匹配的元素的事件(如单击)。也可以绑定自定义事件。 链接文本
$(function(){
    $(".myclass").live("click", function() {
        // do something
    });
});

11
"live"已经被弃用。 - Francisco Corrales Morales

2
如果你使用的是 jQuery 1.3+,那么可以使用 .live()
绑定一个事件处理器(比如 click)到所有当前以及未来匹配的元素上。也可绑定自定义事件。

0

您想要使用live()函数,请参见文档

例如:

$("#anchor1").live("click", function() {
    $("#anchor1").append('<a class="myclass" href="#">test4</a>');
});

"live已被弃用。" - Nardong Bagsik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接