动态添加到DOM的对象不响应jQuery事件

3
我有一个表格,我正在动态添加行,每一行都将有两个单元格,其中一个包含一个输入字段,在此计划使用DatePicker UI来选择日期。问题出现在当我添加新行时,单元格等全部成功添加,但是在点击输入字段时,它却没有显示DatePicker。我阅读了相关资料,得知我应该使用“事件委托”,因为这些新元素并非从一开始就被加载。但是,我一直无法理解如何做到这一点,如果有人能指点我正确的方向,那就太好了。谢谢。
到目前为止,我已经写出了以下代码:
<html>
<head>
<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-    ui.css">
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
<script>
$(document).ready(function() {
  $( ".datepicker" ).datepicker();
  $( "#TheTable" ).on("change",".datepicker",function(){
    $( this ).datepicker( "option", "dateFormat", "yy-mm-dd" );
  });
});

function addRow() {   
    var table = document.getElementById("TheTable");
    var row = table.insertRow(-1);
    var cell1 = row.insertCell(0);
    var cell2 = row.insertCell(1);
    cell1.innerHTML='Date';
    cell2.innerHTML='<input type="text" class="datepicker"/>';
}
</script>
</head>
<body>
<table name="MyTable" id="TheTable">
  <tr>
    <td>Date</td>
    <td><input type="text" class="datepicker" /></td>
  </tr>
  <tr>
  <td>Date</td>
    <td><input type="text" class="datepicker" /></td>
  </tr>
</table>
<input type="button" onClick="return addRow()" value ="Add Another Date">   
</body>
</html>
3个回答

4
$( "#TheTable" ).on("change",".datepicker",function() {

这应该是有效的。

.on() 通过监听父元素上冒泡的事件(见此处有关冒泡的解释 - 第一段),使由新元素触发的事件冒泡到正在被监听的父级。

顺便提一下,最好监听所需元素的最低公共父级,否则 jQuery 将评估不必要的事件。

请参阅.on() 的 jQuery 文档

以下是 .on() 文档的关键点:

.on( events [, selector ] [, data ], handler(eventObject) )

大多数浏览器事件会从文档中发生它们的最深、最内部的元素(事件目标)向上冒泡或传播到 body 和 document 元素。在 Internet Explorer 8 及更低版本中,一些事件如 changesubmit 不会自动冒泡,但 jQuery 会修补它们以实现冒泡和创建一致的跨浏览器行为。

如果省略 selector 或将其设置为 null,则将事件处理程序称为直接绑定直接绑定处理程序。每次所选元素上发生事件时,无论它直接发生在元素上还是从后代(内部)元素冒泡而来,都会调用处理程序。

当提供了 selector 后,事件处理程序被称为委托处理程序。如果事件发生在绑定元素上,则不会调用处理程序,但只有匹配选择器的后代(内部元素)才能调用它。jQuery 将事件从事件目标向上冒泡到附加处理程序的元素(即从最内部到最外部的元素),并运行该路径上任何与选择器匹配的元素的处理程序。

事件处理程序仅绑定到当前选择的元素;它们必须在代码调用 .on() 时存在于页面上。


如果我理解正确,当我提供一个selector时,事件被委托,这意味着事件发生在共享选择器的元素的后代中。根据文档,我有两个选项;要么在新HTML之后选择元素并附加事件处理程序,要么使用委托事件。您提供的代码就是这样做的,它使用委派事件来附加事件处理程序。我理解得对吗?我实现了您的解决方案,但无法使其正常工作。我更新了代码到我现在拥有的内容。我甚至不知道我做错了什么...感谢您的帮助。 - Annatar
是的,你理解得很正确。当你添加元素时,你可以在addRow()函数内部附加一个监听器,但这样做会添加额外的事件监听器;只有一个听起来更好,不是吗?如果你要这样做,记得在删除行时删除监听器!你的代码现在看起来很完美了,除非我看到更多内容,否则我无法提出更多建议。你能给我提供一个实时版本的链接吗? - Bill
啊 - 我找到了你的错误!在它能够工作之前,你必须在新元素上初始化日期选择器。我把所有内容都粘贴到了jsFiddle上,以便我可以调试它,看看我添加到addRow()的最后一行。http://jsfiddle.net/FAcF2/ - Bill
非常感谢,现在它完美地运行了。我有点意识到我需要在新元素上初始化日期选择器才能使其工作,所以我之前的评论问如何做...但是我自己无法弄清楚。再次感谢,祝你编码愉快! - Annatar
请纠正我如果我错了,你是在使用.not()来选择不属于.datepicker类的元素,然后将它们添加到其中吗? - Annatar
当您初始化元素上的日期选择器时,它会自动附加.hasDatepicker类。我使用.not('.hasDatepicker')来避免在已经拥有日期选择器的元素上再次进行初始化。 - Bill

1
你需要监听父元素才能够定位动态绘制的内容。替换为:
$(document).ready(function() {
  $( ".datepicker" ).datepicker();
  $( ".datepicker" ).on("change",function() {
    $( ".datepicker" ).datepicker( "option", "dateFormat", "yy-mm-dd" );
  });
});

使用:

$(document).ready(function() {
  $( ".datepicker" ).datepicker();
  $( '#TheTable' ).on("change",'.datepicker',function() {
    $( this ).datepicker( "option", "dateFormat", "yy-mm-dd" );
  });
});

这与我的答案相同,只是您不需要听整个文档 - 这会使您的脚本变得非常缓慢,特别是对于大页面。您只需要委派最接近的共同父级即可。 - Bill
1
我刚刚注意到了。我编辑了我的答案并点赞了你的。 - Lawren
这不会在新的日期选择器元素上初始化日期选择器。 - Kevin B
对我来说还是不起作用,我应该如何初始化新的日期选择器元素上的datepicker? - Annatar
@Annatar,你看了我的回答吗? - Bill

0

你不需要事件委托;只需在开始时设置选项。然后,在你的函数中,当你添加新元素时,在该元素上触发datepicker方法(使用所需的选项)。

$(".datepicker").datepicker("option", "dateFormat", "yy-mm-dd");

function addRow() {   
    var table = document.getElementById("TheTable");
    var row = table.insertRow(-1);
    var cell1 = row.insertCell(0);
    var cell2 = row.insertCell(1);
    cell1.innerHTML='Date';
    $('<input type="text" class="datepicker"/>')
        .datepicker("option", "dateFormat", "yy-mm-dd")
        .appendTo(cell2);
}

在将日期选择器设置为日期选择器之前,您将如何使用日期选择器选项方法在输入上设置日期选择器选项? - Kevin B

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