如何在jQuery实现的HTML日历中防止多选日期范围重叠?
多日期范围选择日历的逻辑实现与防重叠方案
需求逻辑:
- 第一次点击选择起始日
- 第二次点击选择结束日(必须晚于起始日)
- 第三次点击选择下一个起始日
- 第四次点击选择下一个结束日
希望通过index()方法实现,同时要防止时间范围重叠,以下是当前实现代码:
现有代码
HTML
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <table border="1"> <tr> <td colspan="7"><b>2016</b> </td> </tr> <tr> <td colspan="7"><i>November</i> </td> </tr> <tr> <th>mon</th> <th>tue</th> <th>wed</th> <th>thu</th> <th>fri</th> <th>sat</th> <th>sun</th> </tr> <tr> <td></td> <td class="day">1</td> <td class="day">2</td> <td class="day">3</td> <td class="day">4</td> <td class="day">5</td> <td class="day">6</td> </tr> <tr> <td class="day">7</td> <td class="day">8</td> <td class="day">9</td> <td class="day">10</td> <td class="day">11</td> <td class="day">12</td> <td class="day">13</td> </tr> <tr> <td class="day">14</td> <td class="day">15</td> <td class="day">16</td> <td class="day">17</td> <td class="day">18</td> <td class="day">19</td> <td class="day">20</td> </tr> <tr> <td class="day">21</td> <td class="day">22</td> <td class="day">23</td> <td class="day">24</td> <td class="day">25</td> <td class="day">26</td> <td class="day">27</td> </tr> <tr> <td class="day">28</td> <td class="day">29</td> <td class="day">30</td> <td></td> <td></td> <td></td> <td></td> </tr> </table>
CSS
table { border-collapse: collapse; } table tr td { width: 14%; } table tr td:hover { cursor: pointer; } .firstClick { background: green; } .checkin { background: yellow; } .checkout { background: red; } .reserved { background: blue; }
JavaScript
$("td.day").click(function() { if ($("td.firstClick").length == 0 && $(this).hasClass("reserved") == false) { $(this).addClass("firstClick"); } if ($("td.firstClick").length > 0 && $(this).hasClass("firstClick") == false) { var tds = $("td.day"); var firstClick = $(".firstClick"); var firstClickIndex = tds.index(firstClick); var currentIndex = tds.index(this); tds.filter(function() { var idx = tds.index(this); return idx > firstClickIndex && idx < currentIndex; }).addClass("reserved"); $(".firstClick").addClass("checkin").removeClass("firstClick"); $(this).addClass("checkout"); } });
改进方案(基于index()实现多范围选择与防重叠)
当前代码仅支持单范围选择,要实现多范围并防重叠,需调整状态判断和重叠校验逻辑:
- 状态追踪:用变量记录当前是否在选择起始日,区分多范围下的选择阶段
- 重叠校验:通过
index()判断当前日期是否已被占用,或新范围是否与已有范围重叠 - 边界处理:确保结束日晚于起始日,避免无效选择
修改后的JavaScript代码:
// 标记当前是否处于选择起始日的状态 let isSelectingStart = false; // 存储所有已选日期范围 const selectedRanges = []; $("td.day").click(function() { const $day = $(this); const tds = $("td.day"); const currentIndex = tds.index($day); // 跳过已被占用的日期 if ($day.hasClass('reserved') || $day.hasClass('checkin') || $day.hasClass('checkout')) { return; } if (!isSelectingStart) { // 选择新的起始日 $day.addClass('firstClick'); isSelectingStart = true; } else { const $startDay = $('.firstClick'); const startIndex = tds.index($startDay); // 确保结束日晚于起始日 if (currentIndex <= startIndex) { alert('结束日期必须晚于起始日期'); return; } // 检查新范围是否与已有范围重叠 let isOverlap = false; selectedRanges.forEach(range => { if ((startIndex > range.startIndex && startIndex < range.endIndex) || (currentIndex > range.startIndex && currentIndex < range.endIndex) || (startIndex < range.startIndex && currentIndex > range.endIndex)) { isOverlap = true; } }); if (isOverlap) { alert('该日期范围与已选范围重叠,请重新选择'); $startDay.removeClass('firstClick'); isSelectingStart = false; return; } // 标记日期范围 $startDay.removeClass('firstClick').addClass('checkin'); $day.addClass('checkout'); tds.filter(function() { const idx = tds.index(this); return idx > startIndex && idx < currentIndex; }).addClass('reserved'); // 保存新范围 selectedRanges.push({ startIndex: startIndex, endIndex: currentIndex }); isSelectingStart = false; } });
逻辑说明:
- 状态管理:通过
isSelectingStart变量控制选择阶段,解决多范围选择的流程判断问题 - 重叠校验:遍历已选范围,利用日期的
index值交叉对比,确保新范围不与任何已有范围重叠 - 无效拦截:禁止选择早于起始日的结束日,同时跳过已被标记的日期,避免重复操作
内容的提问来源于stack exchange,提问作者user3270967
相关产品推荐
相关产品推荐

