JavaScript日历切换异常:12月无法跳转至次年1月
日历组件月份切换异常问题修复
问题描述
开发JavaScript日历组件时出现月份切换异常:处于2023年12月时,点击下月按钮无法切换到2024年1月,直接跳转到2024年12月;切换上月时也存在同类错误。
问题根源分析
- 参数赋值逻辑错误:
createCalendar函数开头使用||运算符判断参数是否存在,但当传入的月份为0(对应1月)时,0会被判定为false,导致currentMonth被强制重置为当前系统月份,完全忽略了传入的参数值。 - 重复绑定点击事件:每次调用
createCalendar都会为新生成的<button>元素绑定一次点击事件,多次切换后同一按钮会触发多次月份变更操作,加剧了跳转异常。
修复方案
1. 修正参数赋值逻辑
将currentYear和currentMonth的赋值逻辑改为判断参数是否为undefined,避免合法的0值被误判:
// 替换原createCalendar函数开头的赋值代码 const today = new Date(); currentYear = typeof year !== 'undefined' ? year : today.getFullYear(); currentMonth = typeof month !== 'undefined' ? month : today.getMonth();
2. 移除重复的事件绑定
将按钮点击事件的绑定逻辑移出createCalendar函数,放到DOMContentLoaded的顶层作用域,避免每次重建日历DOM时重复绑定:
// 在createCalendar函数外部添加事件委托(或直接绑定,但委托更稳定) document.addEventListener('click', function(e) { if (e.target.matches('#prevMonth')) { currentMonth--; if (currentMonth < 0) { currentMonth = 11; currentYear--; } createCalendar(currentYear, currentMonth); } else if (e.target.matches('#nextMonth')) { currentMonth++; if (currentMonth > 11) { currentMonth = 0; currentYear++; } createCalendar(currentYear, currentMonth); } });
同时删除createCalendar函数内部的prevMonthBtn和nextMonthBtn的事件绑定代码。
修复后的完整代码
document.addEventListener('DOMContentLoaded', function () { const calendar = document.getElementById("calendar"); let currentYear, currentMonth; const monthNames = [ "Styczeń", "Luty", "Marzec", "Kwiecień", "Maj", "Czerwiec", "Lipiec", "Sierpień", "Wrzesień", "Październik", "Listopad", "Grudzień" ]; const dayNames = ["Pn", "Wt", "Śr", "Czw", "Pt", "Sob", "Nie"]; // 全局事件委托处理月份切换 document.addEventListener('click', function(e) { if (e.target.matches('#prevMonth')) { currentMonth--; if (currentMonth < 0) { currentMonth = 11; currentYear--; } createCalendar(currentYear, currentMonth); } else if (e.target.matches('#nextMonth')) { currentMonth++; if (currentMonth > 11) { currentMonth = 0; currentYear++; } createCalendar(currentYear, currentMonth); } }); function createCalendar(year, month) { const today = new Date(); // 修正参数赋值逻辑 currentYear = typeof year !== 'undefined' ? year : today.getFullYear(); currentMonth = typeof month !== 'undefined' ? month : today.getMonth(); const currentDay = today.getDate(); const daysInMonth = new Date(currentYear, currentMonth + 1, 0).getDate(); const firstDay = new Date(currentYear, currentMonth, 1).getDay() || 7; calendar.innerHTML = ""; const monthName = monthNames[currentMonth]; calendar.innerHTML += `<div class="d-flex title-month"> <button id="prevMonth" class="prevMonth"><<</button> <h2 class="nameOfMonth">${monthName} ${currentYear}</h2> <button id="nextMonth" class="nextMonth">>></button></div> `; const table = document.createElement("table"); let day = 1; const headerRow = document.createElement("tr"); dayNames.forEach(function (dayName) { const th = document.createElement("th"); th.textContent = dayName; headerRow.appendChild(th); }); table.appendChild(headerRow); for (let i = 0; i < 6; i++) { const row = document.createElement("tr"); for (let j = 0; j < 7; j++) { if (i === 0 && j < firstDay - 1) { const cell = document.createElement("td"); row.appendChild(cell); } else if (day <= daysInMonth) { const cell = document.createElement("td"); cell.textContent = day; if (day === currentDay && currentMonth === today.getMonth() && currentYear === today.getFullYear()) { cell.classList.add("today"); } else if (new Date(currentYear, currentMonth, day) < today) { cell.classList.add("past"); } if (j === 5 || j === 6) { cell.classList.add("weekend"); } row.appendChild(cell); day++; if (!(new Date(currentYear, currentMonth, day - 1) <= today)) { cell.addEventListener("click", (event) => { if (!event.target.classList.contains("past")) { const selectedDay = event.target.textContent; openPopup(selectedDay, currentMonth + 1, currentYear); } }); } } } table.appendChild(row); } calendar.appendChild(table); function openPopup(day, month, year) { const popup = document.createElement("div"); popup.classList.add("popup"); popup.innerHTML = ` <form id="bookingForm" method="post" action="/saveBooking"> <input type="hidden" name="selected_date" id="selected_date" value="${year}-${month}-${day}"> <span class="close-button" onclick="closePopup()">X</span> <h3>${day}.${month}.${year}</h3> <select name="category"> <option value="category1">Категорія 1</option> <option value="category2">Категорія 2</option> <option value="category3">Категорія 3</option> </select> <select name="time"> <option value="08:00">08:00</option> <option value="09:00">09:00</option> <option value="10:00">10:00</option> <option value="11:00">11:00</option> <option value="12:00">12:00</option> <option value="13:00">13:00</option> <option value="14:00">14:00</option> <option value="15:00">15:00</option> <option value="16:00">16:00</option> </select> <button type="submit" name="submit">Записатися</button> </form> `; document.body.appendChild(popup); const closeBtn = popup.querySelector(".close-button"); closeBtn.addEventListener("click", function () { closePopup(); }); } function closePopup() { const popup = document.querySelector(".popup"); if (popup) { popup.remove(); } } } createCalendar(); });
内容的提问来源于stack exchange,提问作者Максим Каленюк
相关产品推荐
相关产品推荐

