// 日历状态管理 class CalendarApp { constructor() { this.currentDate = new Date(); this.markedDates = this.loadData(); this.init(); } init() { this.renderCalendar(); this.bindEvents(); } // 获取月份的第一天是星期几(0=周日, 1=周一...) getFirstDayOfMonth(date) { const firstDay = new Date(date.getFullYear(), date.getMonth(), 1); return firstDay.getDay(); } // 获取月份的天数 getDaysInMonth(date) { return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate(); } // 格式化日期为 YYYY-MM-DD 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}`; } // 检查是否为今天 isToday(date) { const today = new Date(); return date.getDate() === today.getDate() && date.getMonth() === today.getMonth() && date.getFullYear() === today.getFullYear(); } // 获取日期标记状态 getDateStatus(date) { const dateStr = this.formatDate(date); return this.markedDates[dateStr] || 'none'; } // 切换日期标记状态 toggleDateStatus(date) { const dateStr = this.formatDate(date); const currentStatus = this.markedDates[dateStr] || 'none'; // 状态循环: none -> completed -> partial -> none let newStatus; switch (currentStatus) { case 'none': newStatus = 'completed'; break; case 'completed': newStatus = 'partial'; break; case 'partial': newStatus = 'none'; break; default: newStatus = 'none'; } if (newStatus === 'none') { delete this.markedDates[dateStr]; } else { this.markedDates[dateStr] = newStatus; } this.saveData(); this.renderCalendar(); } // 渲染日历 renderCalendar() { const calendar = document.getElementById('calendar'); calendar.innerHTML = ''; // 星期标题 const weekdays = ['日', '一', '二', '三', '四', '五', '六']; weekdays.forEach(day => { const weekdayEl = document.createElement('div'); weekdayEl.className = 'weekday'; weekdayEl.textContent = day; calendar.appendChild(weekdayEl); }); // 更新月份显示 const monthNames = ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月']; const monthDisplay = document.getElementById('currentMonth'); monthDisplay.textContent = `${this.currentDate.getFullYear()}年 ${monthNames[this.currentDate.getMonth()]}`; // 获取月份信息 const firstDay = this.getFirstDayOfMonth(this.currentDate); const daysInMonth = this.getDaysInMonth(this.currentDate); const today = new Date(); // 添加上个月的日期(填充空白) const prevMonth = new Date(this.currentDate.getFullYear(), this.currentDate.getMonth() - 1, 0); const daysInPrevMonth = prevMonth.getDate(); for (let i = firstDay - 1; i >= 0; i--) { const day = daysInPrevMonth - i; const date = new Date(this.currentDate.getFullYear(), this.currentDate.getMonth() - 1, day); this.createDayElement(calendar, date, day, true); } // 添加当前月的日期 for (let day = 1; day <= daysInMonth; day++) { const date = new Date(this.currentDate.getFullYear(), this.currentDate.getMonth(), day); this.createDayElement(calendar, date, day, false); } // 添加下个月的日期(填充到完整周) const totalCells = calendar.children.length - 7; // 减去星期标题 const remainingCells = 42 - totalCells; // 6行 x 7列 = 42 for (let day = 1; day <= remainingCells; day++) { const date = new Date(this.currentDate.getFullYear(), this.currentDate.getMonth() + 1, day); this.createDayElement(calendar, date, day, true); } } // 创建日期元素 createDayElement(container, date, dayNumber, isOtherMonth) { const dayEl = document.createElement('div'); dayEl.className = 'day'; if (isOtherMonth) { dayEl.classList.add('other-month'); } if (this.isToday(date)) { dayEl.classList.add('today'); } const status = this.getDateStatus(date); if (status !== 'none') { dayEl.classList.add(status); } const dayNumberEl = document.createElement('div'); dayNumberEl.className = 'day-number'; dayNumberEl.textContent = dayNumber; dayEl.appendChild(dayNumberEl); if (status !== 'none') { const markEl = document.createElement('div'); markEl.className = 'day-mark'; markEl.textContent = status === 'completed' ? '✓' : '○'; dayEl.appendChild(markEl); } // 添加点击事件 dayEl.addEventListener('click', () => { if (!isOtherMonth) { this.toggleDateStatus(date); } }); container.appendChild(dayEl); } // 绑定事件 bindEvents() { document.getElementById('prevMonth').addEventListener('click', () => { this.currentDate.setMonth(this.currentDate.getMonth() - 1); this.renderCalendar(); }); document.getElementById('nextMonth').addEventListener('click', () => { this.currentDate.setMonth(this.currentDate.getMonth() + 1); this.renderCalendar(); }); document.getElementById('todayBtn').addEventListener('click', () => { this.currentDate = new Date(); this.renderCalendar(); }); } // 保存数据到 localStorage saveData() { try { localStorage.setItem('calendarMarkedDates', JSON.stringify(this.markedDates)); } catch (e) { console.error('保存数据失败:', e); } } // 从 localStorage 加载数据 loadData() { try { const data = localStorage.getItem('calendarMarkedDates'); return data ? JSON.parse(data) : {}; } catch (e) { console.error('加载数据失败:', e); return {}; } } } // 初始化应用 document.addEventListener('DOMContentLoaded', () => { new CalendarApp(); });