如何使用JavaScript为D&D网站创建自定义奇幻日历?
自定义D&D日历日期选择器实现方案
核心思路
基于你数据库中的StartWeekday、StartMonth、StartDate、StartYear字段,完全脱离系统原生日期API限制,手动构建自定义日历的计算与渲染逻辑,适配D&D世界的特殊历法规则。
具体实现步骤
1. 定义自定义日历配置
先将数据库中的配置转换为JS对象,统一管理历法规则:
// 从数据库获取的配置示例 const customCalendarConfig = { startWeekday: 1, // 自定义一周起始日,比如1代表周一(可根据需求定义0=周日等) startMonth: 1, // 自定义历法的首个月份 startDate: 1, // 历法的起始日 startYear: 1, // 历法的起始年 months: [ { name: "锤砧月", days: 30 }, { name: "盾卫月", days: 28 }, { name: "猎鹰月", days: 31 }, // 补充所有自定义月份的名称与天数 ] };
2. 实现日历核心计算逻辑
编写函数计算指定年月的日历结构,按周分组并处理空日期占位:
// 获取指定年月的日历数据,返回按周分组的日期数组 function getCustomMonthCalendar(year, monthIndex, config) { const targetMonth = config.months[monthIndex]; const totalDays = targetMonth.days; const firstDayOffset = calculateFirstDayOffset(year, monthIndex, config); const calendarWeeks = []; let currentWeek = new Array(7).fill(null); // 填充当月第一天前的空占位 for (let i = 0; i < firstDayOffset; i++) { currentWeek[i] = null; } // 填充当月所有日期 for (let day = 1; day <= totalDays; day++) { const weekDayPos = (firstDayOffset + day - 1) % 7; currentWeek[weekDayPos] = day; // 每周结束时存入数组并重置 if (weekDayPos === 6) { calendarWeeks.push([...currentWeek]); currentWeek = new Array(7).fill(null); } } // 存入最后一周剩余数据 if (currentWeek.some(item => item !== null)) { calendarWeeks.push(currentWeek); } return { monthName: targetMonth.name, year, weeks: calendarWeeks }; } // 计算当月第一天在自定义周中的位置偏移 function calculateFirstDayOffset(year, monthIndex, config) { // 计算从历法起始日到目标年月第一天的总天数 const yearsPassed = year - config.startYear; const totalDaysInPastYears = yearsPassed * config.months.reduce((sum, month) => sum + month.days, 0); const totalDaysInPastMonths = config.months.slice(0, monthIndex).reduce((sum, month) => sum + month.days, 0); const totalDaysFromStart = totalDaysInPastYears + totalDaysInPastMonths + (config.startDate - 1); // 基于自定义起始周计算偏移 return (totalDaysFromStart + config.startWeekday) % 7; }
3. 动态渲染日历到页面
用JS生成DOM结构,添加日期选中交互:
// 将日历数据渲染到指定容器 function renderCalendar(calendarData) { const container = document.getElementById('custom-date-picker'); container.innerHTML = ''; // 渲染年月标题 const header = document.createElement('div'); header.className = 'calendar-header'; header.textContent = `${calendarData.monthName} ${calendarData.year}`; container.appendChild(header); // 渲染自定义星期标题 const customWeekDays = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']; // 根据startWeekday调整顺序 const weekHeader = document.createElement('div'); weekHeader.className = 'week-header'; customWeekDays.forEach(dayName => { const dayEl = document.createElement('div'); dayEl.className = 'week-day'; dayEl.textContent = dayName; weekHeader.appendChild(dayEl); }); container.appendChild(weekHeader); // 渲染日期格子 const grid = document.createElement('div'); grid.className = 'calendar-grid'; calendarData.weeks.forEach(week => { week.forEach(day => { const dayEl = document.createElement('div'); dayEl.className = day ? 'calendar-day' : 'empty-day'; if (day) { dayEl.textContent = day; // 添加日期选中事件 dayEl.addEventListener('click', () => handleDateSelect(calendarData.year, calendarData.monthIndex, day)); } grid.appendChild(dayEl); }); }); container.appendChild(grid); } // 日期选中回调 function handleDateSelect(year, monthIndex, day) { const selectedMonth = customCalendarConfig.months[monthIndex].name; console.log('选中自定义日期:', `${year}年${selectedMonth}${day}日`); // 此处可将选中日期提交至数据库或绑定到表单 }
4. 基础样式美化(可选)
用CSS调整日历显示效果:
#custom-date-picker { border: 1px solid #ccc; padding: 12px; width: 320px; border-radius: 8px; } .calendar-header { font-size: 1.3em; font-weight: 600; text-align: center; margin-bottom: 10px; } .week-header { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; margin-bottom: 8px; } .week-day { text-align: center; font-weight: 500; color: #555; } .calendar-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; } .calendar-day { padding: 10px; text-align: center; cursor: pointer; border-radius: 4px; transition: background-color 0.2s; } .calendar-day:hover { background-color: #f0f0f0; } .empty-day { padding: 10px; }
关键注意事项
- 如果自定义历法包含闰年、月份天数浮动规则,需要修改
calculateFirstDayOffset中的总天数计算逻辑 - 可添加「上月/下月」切换按钮,调用
getCustomMonthCalendar重新计算并渲染 - 选中日期后,需按照数据库字段格式处理存储逻辑,确保与
StartWeekday等字段关联
内容的提问来源于stack exchange,提问作者dylpickle912
相关产品推荐
相关产品推荐

