预订网站For循环失效:日期无法序列化,AJAX请求疑存问题
预订网站日历生成异常问题
我在开发一个预订网站时遇到了问题:For循环存在异常或逻辑错误,导致日历生成结果不符合预期(附旧版本预期效果截图与新版本实际输出截图)。项目采用PHP开发,其中check_date.php功能正常,问题疑似出在AJAX请求环节。
相关JavaScript代码如下:
// JavaScript code for generating the calendar and handling month navigation const calendarContainer = document.getElementById("calendar"); const prevMonthBtn = document.getElementById("prevMonth"); const nextMonthBtn = document.getElementById("nextMonth"); const currentMonthYear = document.getElementById("currentMonthYear"); const daysOfWeek = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; const months = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ]; const currentDate = new Date(); let currentMonth = currentDate.getMonth(); let currentYear = currentDate.getFullYear(); function generateCalendar() { const daysInMonth = new Date(currentYear, currentMonth + 1, 0).getDate(); const firstDayIndex = new Date(currentYear, currentMonth, 1).getDay(); calendarContainer.innerHTML = ""; // Display days of the week at the top of the calendar for (const dayOfWeek of daysOfWeek) { const dayOfWeekDiv = document.createElement("div"); dayOfWeekDiv.classList.add("day"); dayOfWeekDiv.textContent = dayOfWeek; calendarContainer.appendChild(dayOfWeekDiv); } for (let i = 0; i < firstDayIndex; i++) { const dayDiv = document.createElement("div"); dayDiv.classList.add("day"); calendarContainer.appendChild(dayDiv); } for (let i = 1; i <= daysInMonth; i++) { const dayDiv = document.createElement("a"); dayDiv.href = "entry.php"; let __ryear = currentYear.toString(); let __rmonth = currentMonth.toString(); let daI = i.toString(); let result1 = __ryear.concat(__rmonth); let result2 = result1.concat(daI); // let ruiue = result2; // let date6969 = i; // AJAX request to check if the date exists in the database let xhr = new XMLHttpRequest(); xhr.open("GET", "http://localhost/irctclogin/check_date.php?date=" + result2, true); xhr.onreadystatechange = function() { if (xhr.readyState == 4 && xhr.status == 200) { let response = xhr.responseText; if (response == "exists") { // Date exists in the database, continue the program let bookStatus = "booked"; dayDiv.classList.add("day", result2, bookStatus); dayDiv.textContent = i; calendarContainer.appendChild(dayDiv); // dayDiv.value = i; } else { let bookStatus = "available"; dayDiv.classList.add("day", result2, bookStatus); dayDiv.textContent = i; calendarContainer.appendChild(dayDiv); // dayDiv.value = i; // console.log(i); } } } xhr.send(); } currentMonthYear.textContent = `${months[currentMonth]} ${currentYear}`; // console.log(`${months[currentMonth]} ${currentYear}`); } prevMonthBtn.addEventListener("click", () => { if (currentMonth === 0) { currentMonth = 11; currentYear--; } else { currentMonth--; } generateCalendar(); }); nextMonthBtn.addEventListener("click", () => { if (currentMonth === 11) { currentMonth = 0; currentYear++; } else { currentMonth++; } generateCalendar(); }); generateCalendar();
问题分析
- 异步请求的变量绑定问题:循环中创建的AJAX请求是异步执行的,当回调触发时,循环已经执行完毕,
dayDiv和i都会指向循环最后一次的变量值,导致所有日期节点都被错误地赋值为最后一天的状态。 - 日期格式错误:月份是0基数字(0代表1月),直接转字符串后,1-9月会是单字符(如"1"),拼接后的日期格式不符合常规(比如2024年1月5日会变成"202415"),后端
check_date.php可能无法正确解析该日期,导致状态判断错误。 - 重复绑定事件监听:每次调用
generateCalendar()都会给前后月份按钮添加新的点击事件,多次切换月份后,点击按钮会触发多次generateCalendar(),导致日历渲染混乱。
修复方案与代码
关键修改点
- 使用立即执行函数绑定当前循环的变量,确保每个AJAX回调对应正确的日期节点和日期值;
- 修复日期格式,月份(+1后)和日期不足两位时补0,生成标准的YYYYMMDD格式;
- 将按钮点击事件移到
generateCalendar()外部,只绑定一次,避免重复触发; - 先将日期节点添加到容器,再通过AJAX更新状态,保证日历结构先渲染完整。
修复后的完整代码:
// JavaScript code for generating the calendar and handling month navigation const calendarContainer = document.getElementById("calendar"); const prevMonthBtn = document.getElementById("prevMonth"); const nextMonthBtn = document.getElementById("nextMonth"); const currentMonthYear = document.getElementById("currentMonthYear"); const daysOfWeek = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; const months = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ]; const currentDate = new Date(); let currentMonth = currentDate.getMonth(); let currentYear = currentDate.getFullYear(); function generateCalendar() { const daysInMonth = new Date(currentYear, currentMonth + 1, 0).getDate(); const firstDayIndex = new Date(currentYear, currentMonth, 1).getDay(); calendarContainer.innerHTML = ""; // 渲染星期标题 for (const dayOfWeek of daysOfWeek) { const dayOfWeekDiv = document.createElement("div"); dayOfWeekDiv.classList.add("day"); dayOfWeekDiv.textContent = dayOfWeek; calendarContainer.appendChild(dayOfWeekDiv); } // 填充当月第一天之前的空白格子 for (let i = 0; i < firstDayIndex; i++) { const dayDiv = document.createElement("div"); dayDiv.classList.add("day"); calendarContainer.appendChild(dayDiv); } // 渲染当月每一天 for (let i = 1; i <= daysInMonth; i++) { // 生成标准YYYYMMDD格式的日期字符串 const yearStr = currentYear.toString(); const monthStr = String(currentMonth + 1).padStart(2, '0'); const dayStr = String(i).padStart(2, '0'); const dateStr = yearStr + monthStr + dayStr; const dayDiv = document.createElement("a"); dayDiv.href = "entry.php"; dayDiv.classList.add("day", dateStr); dayDiv.textContent = i; // 用立即执行函数绑定当前循环的节点和日期 (function(targetNode, targetDate) { const xhr = new XMLHttpRequest(); xhr.open("GET", `http://localhost/irctclogin/check_date.php?date=${targetDate}`, true); xhr.onreadystatechange = function() { if (xhr.readyState === 4 && xhr.status === 200) { const response = xhr.responseText.trim(); targetNode.classList.add(response === "exists" ? "booked" : "available"); } }; xhr.send(); })(dayDiv, dateStr); calendarContainer.appendChild(dayDiv); } currentMonthYear.textContent = `${months[currentMonth]} ${currentYear}`; } // 仅绑定一次按钮点击事件 prevMonthBtn.addEventListener("click", () => { currentMonth = currentMonth === 0 ? 11 : currentMonth - 1; currentYear = currentMonth === 11 ? currentYear - 1 : currentYear; generateCalendar(); }); nextMonthBtn.addEventListener("click", () => { currentMonth = currentMonth === 11 ? 0 : currentMonth + 1; currentYear = currentMonth === 0 ? currentYear + 1 : currentYear; generateCalendar(); }); // 初始化日历 generateCalendar();
内容的提问来源于stack exchange,提问作者Harshvardhan Sinha
相关产品推荐
相关产品推荐

