You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 03:18:24