Лучшим подходом было бы делегировать событие, что означает его перехват по мере его появления на родительском узле.
делегирование - обзор
Это решение более надежное и эффективное.
Это позволяет обрабатывать событие, даже если позднее в таблицу динамически добавляется больше строк, а также приводит к присоединению одного обработчика события к родительскому узлу (элемент table
) вместо одного для каждого дочернего узла ( tr
элемент).
Если предположить, что пример OP является упрощенным, структура таблицы может быть более сложной, например:
<table id="indexedTable">
...
<tr>
<td><p>1</p></td>
<td>2</td>
<td><p>3</p></td>
</tr>
</table>
Следовательно, упрощенный подход, такой как получение e.target.parentElement
, не будет работать, так как щелчок по внутреннему <p>
и нажатие по центру <td>
приведут к другим результатам.
Использование делегирования нормализует обработку событий, только при условии, что нет вложенных таблиц.
осуществление
Оба следующих фрагмента эквивалентны:
$("#indexedTable").delegate("tr", "click", function(e) {
console.log($(e.currentTarget).index() + 1);
});
$("#indexedTable").on("click", "tr", function(e) {
console.log($(e.currentTarget).index() + 1);
});
Они прикрепляют слушателя к элементу table
и обрабатывают любое событие, всплывающее из строк таблицы. Текущий API является методом on
, а метод delegate
является устаревшим API (и фактически вызывает on
за кулисами).
Обратите внимание, что порядок параметров для обеих функций различен.
пример
Сравнение между прямым обработчиком и делегированием доступно ниже или на jsFiddle:
$("#table-delegate").on("click", "tr", function(e) {
var idx = $(e.currentTarget).index() + 1;
$("#delegation-idx").text(idx);
console.log('delegated', idx);
});
$("#table-direct tr").on("click", function(e) {
var idx = $(e.currentTarget).index() + 1;
$("#direct-idx").text(idx);
console.log('direct', idx);
});
$('[data-action=add-row]').click(function(e) {
var id = e.target.dataset.table;
$('#' + id + ' tbody')
.append($('<tr><td>extra</td><td>extra</td><td>extra</td></tr>')[0])
});
tr:hover{
background:#ddd;
}
button.add-row {
margin-bottom: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>
<h1>Event handling test</h1>
<p>Add rows to both tables and see the difference in handling.</p>
<p>Event delegation attaches a single event listener and events related to newly added children are caught.</p>
<p>Direct event handling attaches an event handler to each child, where children added after the inital handler attachment don't have a handler attached to them, and therefore their indices won't be logged to console.</p>
<h2>Delegation</h2>
<p><span>row index: </span><span id="delegation-idx">unknown</span></p>
<button class="add-row" data-action="add-row" data-table="table-delegate">Add row to delegation</button>
<table id="table-delegate" class="table">
<tbody>
<tr>
<td>normal</td>
<td>normal</td>
<td>normal</td>
</tr>
<tr>
<td><p>nested</p></td>
<td><p>nested</p></td>
<td><p>nested</p></td>
</tr>
<tr>
<td>normal</td>
<td>normal</td>
<td><p>nested</p></td>
</tr>
</table>
<h2>Direct attachment</h2>
<p><span>row index: </span><span id="direct-idx">unknown</span></p>
<button class="add-row" data-action="add-row" data-table="table-direct">Add row to direct</button>
<table id="table-direct" class="table">
<tbody>
<tr>
<td>normal</td>
<td>normal</td>
<td>normal</td>
</tr>
<tr>
<td><p>nested</p></td>
<td><p>nested</p></td>
<td><p>nested</p></td>
</tr>
<tr>
<td>normal</td>
<td>normal</td>
<td><p>nested</p></td>
</tr>
</tbody>
</table>
Вот демоверсия для jsFiddle .
P.S:
Если у вас есть вложенные таблицы (или, в общем случае, вы хотите делегировать элементы с определенной глубиной), вы можете использовать это предложение из отчета об ошибке jQuery .