jQuery如何将onclick事件绑定到动态添加的HTML元素上

150

我想将一个onclick事件绑定到我使用jQuery动态插入的元素上

但它从来没有运行过绑定的函数。如果您能指出为什么这个示例不起作用,以及如何使其正常运行,我会很高兴:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"        
            "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
        <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="da" lang="da">
        <head>
          <title>test of click binding</title>

<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
          <script type="text/javascript">


        jQuery(function(){
          close_link = $('<a class="" href="#">Click here to see an alert</a>');
          close_link.bind("click", function(){
            alert('hello from binded function call');
            //do stuff here...
          });
  
          $('.add_to_this').append(close_link);
        });
          </script>
        </head>
        <body>
          <h1 >Test of click binding</h1>
          <p>problem: to bind a click event to an element I append via JQuery.</p>

          <div class="add_to_this">
            <p>The link is created, then added here below:</p>
          </div>

          <div class="add_to_this">
            <p>Another is added here below:</p>
          </div>


        </body>
        </html>

编辑:我编辑了示例以包含其插入的两个元素。在这种情况下,alert() 调用将永远不会执行。(感谢 @Daff 在评论中指出)


1
当我在Firefox 3.5中测试您的示例页面时,它运行良好。 - Daff
@Daff 很不幸,你是对的!看来我提取了实际可用的代码部分。感谢你指出这一点! - Jesper Rønn-Jensen
@Daff,我编辑了这个示例,所以它包含两个插入方法的位置。然后它_真的_停止工作了 :) - Jesper Rønn-Jensen
9个回答

340

所有这些方法都已被弃用。你应该使用on方法来解决问题。

如果你想要定位一个动态添加的元素,你需要使用

$(document).on('click', selector-to-your-element , function() {
     //code here ....
});

这个方法替代了已经过时的.live()方法。


18
*selector-to-your-element* 应为 '.some-class''#some-id' - Alan Shortis
жҲ‘зҡ„й—®йўҳжҳҜжҲ‘еҒҡзҡ„зұ»дјјдәҺ $('.row').on('click', function(){...}); иҖҢдёҚжҳҜ $(document).on('click','.row',function(){...});гҖӮ - Vishnoo Rath
8
记住,$(document) 可以是您页面上不会更改的任何元素。这可以防止事件冒泡过度,加速 JS 执行速度。例如,将 $(document) 改为 $('.example-container') - Ricky Boyce
1
详细解释 - https://dev59.com/nHVC5IYBdhLWcg3wtzqs动态创建元素上的事件绑定 - Alexei Levenkov
@RickyBoyce 绝妙的提示,谢谢。 - rasputin
我怎么知道一个元素是否是列表? - Matteo

73

首先的问题是,当你对一个包含多个元素的jQuery集合调用append方法时,会为每个元素创建一个克隆元素,因此附加的事件观察器会丢失。

另一种可行的方法是为每个元素创建链接:

function handler() { alert('hello'); }
$('.add_to_this').append(function() {
  return $('<a>Click here</a>').click(handler);
})

另一个潜在的问题可能是事件观察器在元素添加到DOM之前被附加。我不确定这是否有任何影响,但我认为行为可能被视为不确定的。 更可靠的方法可能是:

function handler() { alert('hello'); }
$('.add_to_this').each(function() {
  var link = $('<a>Click here</a>');
  $(this).append(link);
  link.click(handler);
});

2
当您需要绑定其他函数附加的元素上的点击时,可能会出现问题。这就是为什么我建议使用aM1Ne的答案。 - Edoardoo
2
实际上,当你的目标是已知的由其他代码创建的标记结构时,这种方法很有效。但在这里,他自己插入了元素,并且没有明确的选择器(只是一个锚点,可能有很多),因此他必须添加额外的标记才能定位到该元素。在这种情况下,直接将处理程序附加到元素上就像捕获所有点击并测试选择器匹配一样容易。 - Tobias
我理解你的回答,不是说它是错误的。当然,能够动态注入一些HTML(例如使用Ajax加载的无限滚动图片列表)并已经将按钮绑定到某些操作(例如lightbox),这样会更加舒适。 - Edoardoo
2
这个答案对于默认提供较旧版本的jQuery(例如Drupal 7)也非常有帮助。on()是在jQuery 1.7中引入的。 - Wtower

50

Live 方法怎么样?

$('.add_to_this a').live('click', function() {
    alert('hello from binded function call');
});

尽管如此,你所做的看起来应该是有效的。这里有一个相似的帖子


你说得对,它确实有效。是我的错误。所以我已经编辑了问题。 - Jesper Rønn-Jensen
是的,这种问题正是直播活动旨在解决的。 - Powerlord
问题与实时事件无关,尽管在这种情况下,实时事件可以解决它。Daff提供的答案也解决了问题,并且没有将新概念引入方程式中。 - Jesper Rønn-Jensen
我还可以补充一点,目前这是绑定事件的事实标准方式。因此,今天我也会使用live()来代替bind() - Jesper Rønn-Jensen
26
live()已被弃用,建议使用on()代替。链接 - TrophyGeek
1
在jQuery 1.9中,live() 已被弃用并替换为 on() - Walter Roman

25
A little late to the party but I thought I would try to clear up some common misconceptions in jQuery event handlers. As of jQuery 1.7, .on() should be used instead of the deprecated .live(), to delegate event handlers to elements that are dynamically created at any point after the event handler is assigned.
That said, it is not a simple of switching live for on because the syntax is slightly different:
New method (example 1):
$(document).on('click', '#someting', function(){

});

已弃用的方法(例2):

$('#something').live(function(){

});

如上所示,存在差异。关键在于.on()可以通过将选择器传递给jQuery函数本身来类似于.live()地调用:
示例3:
$('#something').on('click', function(){

});

然而,如果不像示例1一样使用$(document),则示例3将无法用于动态创建的元素。如果您不需要动态委托,则示例3非常好。

所有事件都应该使用 $(document).on() 吗?

这样做可以工作,但是如果您不需要动态委托,则最好使用示例3,因为示例1需要浏览器稍微多做一些工作。对性能没有真正影响,但是使用最合适的方法对您的使用来说更有意义。

如果不需要动态委托,应该使用 .on() 而不是 .click() 吗?

不一定。以下只是示例3的快捷方式:

$('#something').click(function(){

});

上面的内容是完全有效的,所以在不需要动态委托时使用哪种方法实际上是个人偏好的问题。
参考资料:
- jQuery文档关于.on() - jQuery文档关于.click() - jQuery文档关于.live()

2

请考虑以下内容:

jQuery(function(){
  var close_link = $('<a class="" href="#">Click here to see an alert</a>');
      $('.add_to_this').append(close_link);
      $('.add_to_this').children().each(function()
      {
        $(this).click(function() {
            alert('hello from binded function call');
            //do stuff here...
        });
      });
});

它可以工作,因为您将其附加到每个特定元素。这就是为什么在将链接添加到DOM后,您需要找到一种明确选择已添加元素作为DOM中的JQuery元素并将单击事件绑定到它的方法。

最好的方式可能是-如建议的那样-通过live方法将其绑定到特定类。


谢谢回答,Daff。不可能只能给DOM中的元素添加事件监听器。不过,我现在会暂时修改我的代码来实现这个功能。(应该没问题,因为我只是为添加的链接添加了特殊的CSS类)。 - Jesper Rønn-Jensen
是的,你说得对,它并不是DOM(实际上它可以使用一个),抱歉。但是我也发现绑定动态创建的元素似乎非常麻烦,只要它们不能被明确的jQuery选择器选择到。 - Daff
BOUND函数调用中的问候。抱歉,这篇文章(整个页面;问题和答案)中有太多这样的内容,我只是想帮忙,你知道,澄清一下。 - Scott Fraley

2

有时需要在元素上创建点击事件,这是可能的,有时也是必要的。例如,在选择器绑定不可行时。关键部分是避免Tobias所说的问题,方法是使用.replaceWith()来替换单个元素。注意,这只是一个概念证明。

<script>
    // This simulates the object to handle
    var staticObj = [
        { ID: '1', Name: 'Foo' },
        { ID: '2', Name: 'Foo' },
        { ID: '3', Name: 'Foo' }
    ];
    staticObj[1].children = [
        { ID: 'a', Name: 'Bar' },
        { ID: 'b', Name: 'Bar' },
        { ID: 'c', Name: 'Bar' }
    ];
    staticObj[1].children[1].children = [
        { ID: 'x', Name: 'Baz' },
        { ID: 'y', Name: 'Baz' }
    ];

    // This is the object-to-html-element function handler with recursion
    var handleItem = function( item ) {
        var ul, li = $("<li>" + item.ID + " " + item.Name + "</li>");

        if(typeof item.children !== 'undefined') {
            ul = $("<ul />");
            for (var i = 0; i < item.children.length; i++) {
                ul.append(handleItem(item.children[i]));
            }
            li.append(ul);
        }

        // This click handler actually does work
        li.click(function(e) {
            alert(item.Name);
            e.stopPropagation();
        });
        return li;
    };

    // Wait for the dom instead of an ajax call or whatever
    $(function() {
        var ul = $("<ul />");

        for (var i = 0; i < staticObj.length; i++) {
            ul.append(handleItem(staticObj[i]));
        }

        // Here; this works.
        $('#something').replaceWith(ul);
    });
</script>
<div id="something">Magical ponies ♥</div>

1
    function load_tpl(selected=""){
        $("#load_tpl").empty();
        for(x in ds_tpl){
            $("#load_tpl").append('<li><a id="'+ds_tpl[x]+'" href="#" >'+ds_tpl[x]+'</a></li>');
        }
        $.each($("#load_tpl a"),function(){
            $(this).on("click",function(e){
                alert(e.target.id);
            });
        });
    }

0

我相信做法正确的方式是:

$('#id').append('<a id="#subid" href="#">...</a>');
$('#subid').click( close_link );

我不能使用 #id 来添加元素,因为我想对许多元素执行此操作。请参见更新的代码示例 :) - Jesper Rønn-Jensen

-1
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>    
<script>
    $(document).ready(function(){
        $(document).on('click', '.close', function(){
            var rowid='row'+this.id;
            var sl = '#tblData tr[id='+rowid+']';
            console.log(sl);
            $(sl).remove();
        });
        $("#addrow").click(function(){
            var row='';
            for(var i=0;i<10;i++){
                row=i;
                row='<tr id=row'+i+'>'
                    +   '<td>'+i+'</td>'
                    +   '<td>ID'+i+'</td>'
                    +   '<td>NAME'+i+'</td>'
                    +   '<td><input class=close type=button id='+i+' value=X></td>'
                    +'</tr>';
                console.log(row);
                $('#tblData tr:last').after(row);
            }
        });
    });

</script>
</head>
  <body>
    <br/><input type="button" id="addrow" value="Create Table"/>
    <table id="tblData" border="1" width="40%">
        <thead>
        <tr>
            <th>Sr</th>
            <th>ID</th>
            <th>Name</th>
            <th>Delete</th>
        </tr>
        </thead>
    </table>
    </body>
 </html>

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