HTML表格行缺少由CSS类绑定的事件监听器
我有一个HTML表格,想让用户能够添加行。把HTML重新格式化得更美观之后,当他们通过从模板行复制来添加一行时,新行上的CSS类绑定的事件监听器就不再起作用了。
请注意,模板行现在来自一个独立的表格(为了让HTML看起来更整洁)。我到底哪里做错了?
例如:
<table id='template' class='financial'>
<tr id='template-row'><td class='updateable'></td></tr>...
<!-- ... -->
</table>
<table id='table-for-adding-rows>
<tr id='original-row'><td class='updateable'></td></tr>
<!-- this row was copied from 'template-row' -->
<tr id='added-row-1'><td class='updateable'></td></tr>
<!-- ... -->
$('.financial .updateable').change(function() { modifyItem(this); });
modifyItem() 在“table-for-adding-rows”中的原始行上被调用,但对从表格“template”添加的行并未调用。
解决方案
首先,需要对术语做一个小小的纠正。你贴出的CSS实际上是JavaScript,尽管 jQuery API使用CSS选择器 来定位元素。
jQuery并没有忘记事件处理程序。在 $(string).change(function) 被调用时,jQuery会直接把事件处理程序附加到匹配CSS选择器的元素上。对文档结构以任何方式进行修改后,新增的行上就不会再有这些事件处理程序。你需要逐一添加它们、在现有表格中克隆一行,或者使用事件代理,这可以通过 $.on(string) 函数实现。
使用 $.clone 来追加新行
<table id='table-for-adding-rows' class='financial'>
<tr id='template' style='display: none'>
<td class='updateable'></td>
</tr>
<tr id='original-row'>
<td class='updateable'>...</td>
</tr>
</table>
你需要在你正在修改的表格中放置模板行。接下来,在用于添加新行的代码中,克隆模板行:
let newRow = $('#template').clone(true);
let table = $('#table-for-adding-rows');
table.append(newRow);
请注意,.clone(true) 是你要的重载方式,这样jQuery也会克隆事件处理程序。
使用 $.on() 来追加新行(例如事件代理)
我偏好的做法是使用 事件代理;也就是把 “change” 处理程序挂到一个祖先元素上,该祖先元素会对来自子元素的冒泡事件做出响应。在这种情况下,把 “change” 处理程序挂到 <table> 元素上。$.on() 函数让这一步变得相当简单,因为它本质上会对匹配选择器的元素进行事件过滤。既然你想监听 .updateable 元素上的change事件,请按下面这样修改你的JavaScript:
$('#table-for-adding-rows').on('change', '.updateable', event => modifyItem(this));
你很可能需要把 modifyItem 函数改为使用 event.currentTarget 来引用被更改的元素。
备选方案
我看到有多人建议使用事件代理,你可以将它用于多个容器,例如
let elements = $(yourselectorhere);
for (let item of $('#table-for-adding-rows')) {
$(item).on('change', '.updateable', function() {
modifyItem(this);
});
}
所以如果你拥有#table1、#table2、#table3,那么这将是你的选择器。另一种做法是这样:
function initializeUpdateable(context) {
let innerContext = context.find(".updatetable:not(.initialized)");
innerContext.change(function() {
modifyItem(this);
});
innerContext.addClass("initialized");
}
并在需要添加新项时对 context 调用它。