jQuery表格日期筛选:解决input type="date"事件触发问题
在网页开发中,表格数据的日期筛选是常见需求,我们通常会使用<input type="date">标签作为日期选择器,配合jQuery实现筛选逻辑。但在实际开发中,很多开发者会遇到<input type="date">的事件触发异常问题,导致筛选功能无法正常工作。本文将针对这个问题展开分析,并提供可行的解决方案。
问题场景复现
假设我们有一个员工信息表格,需要实现根据入职日期筛选表格数据的功能,页面结构如下:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>员工信息表格</title>
<script src="https://www.ipipp.com/jquery-3.6.0.min.js"></script>
<style>
table {
border-collapse: collapse;
width: 100%;
}
th, td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
}
th {
background-color: #f2f2f2;
}
.filter-section {
margin-bottom: 16px;
}
</style>
</head>
<body>
<div class="filter-section">
<label for="startDate">入职日期起始:</label>
<input type="date" id="startDate">
<label for="endDate">入职日期结束:</label>
<input type="date" id="endDate">
<button id="filterBtn">筛选</button>
</div>
<table id="employeeTable">
<thead>
<tr>
<th>姓名</th>
<th>入职日期</th>
<th>部门</th>
</tr>
</thead>
<tbody>
<tr>
<td>张三</td>
<td>2023-01-15</td>
<td>技术部</td>
</tr>
<tr>
<td>李四</td>
<td>2023-03-20</td>
<td>产品部</td>
</tr>
<tr>
<td>王五</td>
<td>2023-05-10</td>
<td>运营部</td>
</tr>
<tr>
<td>赵六</td>
<td>2023-07-08</td>
<td>技术部</td>
</tr>
</tbody>
</table>
</body>
</html>很多开发者会尝试直接监听<input type="date">的change事件来实现实时筛选,初始代码可能如下:
$(function() {
$('#startDate, #endDate').on('change', function() {
filterTable();
});
function filterTable() {
var startDate = $('#startDate').val();
var endDate = $('#endDate').val();
$('#employeeTable tbody tr').each(function() {
var dateStr = $(this).find('td').eq(1).text();
var rowDate = new Date(dateStr);
var showRow = true;
if (startDate) {
var start = new Date(startDate);
if (rowDate < start) {
showRow = false;
}
}
if (endDate) {
var end = new Date(endDate);
if (rowDate > end) {
showRow = false;
}
}
$(this).toggle(showRow);
});
}
});事件触发异常的原因分析
上述代码看似逻辑正确,但实际使用中会出现几种异常情况:
部分浏览器中,手动清空<input type="date">的值时,
change事件不会触发,导致筛选逻辑不执行。当用户通过键盘修改日期输入框的值,且未失去焦点时,
change事件不会触发,筛选结果无法及时更新。如果页面动态生成了<input type="date">元素,直接使用
on绑定的事件会失效,因为事件绑定在初始化时已经执行,无法作用于后续生成的元素。
解决方案
方案一:使用input事件替代change事件
input事件会在输入框的值发生变化时立即触发,无论是通过选择器选择、手动输入还是清空操作,都能正常捕获,比change事件的触发时机更及时。修改事件绑定代码如下:
$(function() {
// 使用input事件监听日期变化
$('#startDate, #endDate').on('input', function() {
filterTable();
});
function filterTable() {
var startDate = $('#startDate').val();
var endDate = $('#endDate').val();
$('#employeeTable tbody tr').each(function() {
var dateStr = $(this).find('td').eq(1).text();
// 将日期字符串转换为时间戳方便比较
var rowTimestamp = new Date(dateStr).getTime();
var showRow = true;
if (startDate) {
var startTimestamp = new Date(startDate).getTime();
if (rowTimestamp < startTimestamp) {
showRow = false;
}
}
if (endDate) {
var endTimestamp = new Date(endDate).getTime();
// 结束日期需要包含当天,所以加一天的时间戳
if (rowTimestamp > endTimestamp + 86400000) {
showRow = false;
}
}
$(this).toggle(showRow);
});
}
});方案二:事件委托解决动态元素绑定问题
如果<input type="date">是动态生成的,需要使用事件委托的方式绑定事件,将事件绑定到静态父元素上,确保动态生成的元素也能触发事件:
$(function() {
// 事件委托,绑定到body或者更近的静态父容器
$(document).on('input', '#startDate, #endDate', function() {
filterTable();
});
function filterTable() {
var startDate = $('#startDate').val();
var endDate = $('#endDate').val();
$('#employeeTable tbody tr').each(function() {
var dateStr = $(this).find('td').eq(1).text();
var rowTimestamp = new Date(dateStr).getTime();
var showRow = true;
if (startDate) {
var startTimestamp = new Date(startDate).getTime();
if (rowTimestamp < startTimestamp) {
showRow = false;
}
}
if (endDate) {
var endTimestamp = new Date(endDate).getTime();
if (rowTimestamp > endTimestamp + 86400000) {
showRow = false;
}
}
$(this).toggle(showRow);
});
}
});方案三:添加筛选按钮兜底
为了提升用户体验,避免事件触发异常导致筛选失败,可以保留筛选按钮,作为兜底方案,用户点击按钮时强制触发筛选逻辑:
$(function() {
// 输入框变化触发筛选
$(document).on('input', '#startDate, #endDate', function() {
filterTable();
});
// 按钮点击触发筛选,兜底处理
$('#filterBtn').on('click', function() {
filterTable();
});
function filterTable() {
var startDate = $('#startDate').val();
var endDate = $('#endDate').val();
$('#employeeTable tbody tr').each(function() {
var dateStr = $(this).find('td').eq(1).text();
var rowTimestamp = new Date(dateStr).getTime();
var showRow = true;
if (startDate) {
var startTimestamp = new Date(startDate).getTime();
if (rowTimestamp < startTimestamp) {
showRow = false;
}
}
if (endDate) {
var endTimestamp = new Date(endDate).getTime();
if (rowTimestamp > endTimestamp + 86400000) {
showRow = false;
}
}
$(this).toggle(showRow);
});
}
});注意事项
日期比较时,建议将日期转换为时间戳再进行比较,避免不同浏览器对日期字符串解析差异导致的问题。
结束日期筛选时,需要加上一天的时间戳(86400000毫秒),确保当天的日期能被包含在筛选结果中。
如果表格数据量较大,频繁触发筛选可能会影响性能,可以添加防抖处理,减少筛选函数的执行频率。
通过上述方案,我们可以有效解决<input type="date">事件触发异常的问题,实现稳定可靠的jQuery表格日期筛选功能。