求基于指定数组开发可滚动周视图预约日历的实现方案
周视图预约日历实现指导
一、生成日期范围数组(过去50天至未来50天)
先写工具函数生成指定范围的日期数组,格式统一为YYYY-MM-DD,和预约数据的JobDate对齐:
function generateDateRange(daysBefore, daysAfter) { const dateRange = []; const today = new Date(); // 生成过去的日期 for (let i = daysBefore; i > 0; i--) { const date = new Date(today); date.setDate(today.getDate() - i); dateRange.push(formatDate(date)); } // 加入今天 dateRange.push(formatDate(today)); // 生成未来的日期 for (let i = 1; i <= daysAfter; i++) { const date = new Date(today); date.setDate(today.getDate() + i); dateRange.push(formatDate(date)); } return dateRange; } // 辅助函数:将Date对象转为YYYY-MM-DD格式 function formatDate(date) { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); return `${year}-${month}-${day}`; } // 生成目标数组:过去50天到未来50天 const dateArray = generateDateRange(50, 50);
二、预处理预约数据:按日期分组并排序
提前对预约数据做分组和排序,避免渲染时重复计算,提升性能:
const appointments = [ { "JobId": 83259, "JobDate": "2023-03-14", "StartTime": "2023-03-14 08:11:58.000" }, { "JobId": 83297, "JobDate": "2023-03-12", "StartTime": "2023-03-12 11:35:00.000" }, { "JobId": 83307, "JobDate": "2023-03-13", "StartTime": "2023-03-13 07:29:07.000" }, { "JobId": 83308, "JobDate": "2023-03-13", "StartTime": "2023-03-13 07:29:51.000" } ]; // 按JobDate分组,每组内按StartTime升序排列 const groupedAppointments = appointments.reduce((acc, appt) => { const date = appt.JobDate; if (!acc[date]) { acc[date] = []; } acc[date].push(appt); // 按StartTime排序 acc[date].sort((a, b) => new Date(a.StartTime) - new Date(b.StartTime)); return acc; }, {});
三、渲染周视图(手动时间槽版)
假设手动定义时间槽为7:00到18:00,每半小时一个,先定义时间槽数组,再遍历日期数组生成对应列,填充时间槽和预约:
1. 定义时间槽
// 手动生成时间槽,格式为HH:mm const timeSlots = []; for (let hour = 7; hour < 18; hour++) { timeSlots.push(`${String(hour).padStart(2, '0')}:00`); timeSlots.push(`${String(hour).padStart(2, '0')}:30`); } // 加入18:00 timeSlots.push('18:00');
2. 渲染DOM结构
<!-- 容器:横向滚动 --> <div class="calendar-container" style="overflow-x: auto; white-space: nowrap;"> <div id="calendar-content"></div> </div>
const calendarContent = document.getElementById('calendar-content'); // 遍历日期数组,生成每个日期列 dateArray.forEach(date => { // 创建日期列容器 const dateColumn = document.createElement('div'); dateColumn.className = 'date-column'; dateColumn.style.display = 'inline-block'; dateColumn.style.width = '180px'; dateColumn.style.border = '1px solid #eee'; dateColumn.style.verticalAlign = 'top'; // 添加日期标题 const dateTitle = document.createElement('div'); dateTitle.className = 'date-title'; dateTitle.style.padding = '8px'; dateTitle.style.textAlign = 'center'; dateTitle.style.backgroundColor = '#f5f5f5'; dateTitle.textContent = date; dateColumn.appendChild(dateTitle); // 获取当前日期的预约 const dateAppointments = groupedAppointments[date] || []; // 遍历时间槽,生成每个时段区块 timeSlots.forEach(slot => { const slotBlock = document.createElement('div'); slotBlock.className = 'slot-block'; slotBlock.style.height = '60px'; slotBlock.style.borderBottom = '1px solid #eee'; slotBlock.style.position = 'relative'; // 添加时间标签 const slotLabel = document.createElement('div'); slotLabel.className = 'slot-label'; slotLabel.style.fontSize = '12px'; slotLabel.style.padding = '4px'; slotLabel.textContent = slot; slotBlock.appendChild(slotLabel); // 匹配当前时间槽的预约 const slotStart = new Date(`${date}T${slot}:00`); const slotEnd = new Date(slotStart.getTime() + 30 * 60 * 1000); // 半小时跨度 const matchedAppts = dateAppointments.filter(appt => { const apptTime = new Date(appt.StartTime); // 判断预约是否落在当前时间槽内(或起始于该槽) return apptTime >= slotStart && apptTime < slotEnd; }); // 渲染预约卡片 matchedAppts.forEach(appt => { const apptCard = document.createElement('div'); apptCard.className = 'appointment-card'; apptCard.style.backgroundColor = '#e3f2fd'; apptCard.style.margin = '4px'; apptCard.style.padding = '4px'; apptCard.style.fontSize = '12px'; apptCard.style.borderRadius = '4px'; apptCard.textContent = `Job ${appt.JobId}`; slotBlock.appendChild(apptCard); }); dateColumn.appendChild(slotBlock); }); calendarContent.appendChild(dateColumn); });
四、优化滚动体验
- 设置容器滚动对齐,让滚动时自动对齐日期列:
.calendar-container { overflow-x: auto; white-space: nowrap; scroll-snap-type: x mandatory; } .date-column { scroll-snap-align: start; }
- 可额外添加上周/下周按钮,通过修改容器的
scrollLeft值控制滚动,或监听滚动事件显示当前可见日期范围。
内容的提问来源于stack exchange,提问作者Tony
相关产品推荐
相关产品推荐

