
本文教你用原生 javascript 实现一个始终显示连续7天(周一到周日)、星期名称位置固定、仅日期数字动态更新的响应式周历,适配荷兰语本地化,并修复原始代码中日期越界、循环逻辑错误及 dom 操作问题。
本文教你用原生 javascript 实现一个始终显示连续7天(周一到周日)、星期名称位置固定、仅日期数字动态更新的响应式周历,适配荷兰语本地化,并修复原始代码中日期越界、循环逻辑错误及 dom 操作问题。
在构建轻量级周视图日历时,核心需求是:星期栏(如 'Ma', 'Di', 'Woe', 'Do', 'Vrij', 'Za', 'Zo')位置绝对固定,而对应日期数字随当前日期自动滚动更新——而非简单叠加 +i(这会导致跨月/跨年错误)。原始代码存在三个关键缺陷:
- for (var i = 0; i < 5; i++) 仅循环5次,但需覆盖7天;
- today.getDate() + i 未处理月末/月初边界(如1月31日+2天 → 2月2日,但原始逻辑仍显示“33”“34”);
- 未重置 Date 对象状态,导致后续日期计算失准。
以下是优化后的完整实现(含 HTML、CSS、JS):
用于 inference.sh 的 JavaScript/TypeScript SDK,可运行 AI 应用、构建代理、集成 150+ 模型。包名:@inferencesh/sdk(npm install),完整 TypeScript 支持。
✅ 正确的初始化逻辑
首先将 Date 对象回拨至本周一(荷兰习惯以周一为每周起始),再逐日递增生成7个 <div>:
<div id="calendar"> <p>Month & year values</p> <div></div> </div>
#calendar {
min-width: 24em;
max-width: 24em;
font-family: system-ui, sans-serif;
}
#calendar > p {
font-weight: bold;
letter-spacing: .2ch;
padding-left: 1em;
margin: 0;
}
#calendar > div {
display: flex;
flex-direction: row;
justify-content: space-around;
margin-top: 0.5em;
}
#calendar > div > div {
background-color: #e6f7ff;
text-align: center;
width: 3rem;
border-radius: 4px;
padding: 0.2em 0;
}
#calendar > div > div > div:first-of-type {
font-style: oblique;
font-size: 0.9em;
color: #555;
margin-bottom: 0.2em;
}
#calendar > div > div > div:last-of-type {
font-weight: bold;
font-size: 1.1em;
}
.active {
background-color: #ff6b6b !important;
color: white;
}const daysOfWeek = ['Ma', 'Di', 'Woe', 'Do', 'Vrij', 'Za', 'Zo'];
const monthNames = [
'Januari', 'Februari', 'Maart', 'April', 'Mei', 'Juni',
'Juli', 'Augustus', 'September', 'Oktober', 'November', 'December'
];
const daysContainer = document.querySelector('#calendar > div');
const monthElement = document.querySelector('#calendar > p');
function generateWeekDays() {
const today = new Date();
const currentDay = today.getDate();
const currentMonth = today.getMonth();
const currentYear = today.getFullYear();
// ? 关键修正:将日期设为本周一(荷兰周起始)
// getDay() 返回 0(Sun)~6(Sat),周一为1 → 需减去 (currentDayOfWeek + 6) % 7 天
const mondayOffset = (today.getDay() + 6) % 7; // 若今天是周日(0),则 offset=6 → 回拨6天到周一
const weekStart = new Date(today);
weekStart.setDate(today.getDate() - mondayOffset);
// 更新月份标题(含年份,避免歧义)
monthElement.textContent = `${monthNames[currentMonth]} - ${currentYear}`;
// 清空容器
daysContainer.innerHTML = '';
// 生成7天:从周一到周日
for (let i = 0; i < 7; i++) {
const dayDate = new Date(weekStart);
dayDate.setDate(weekStart.getDate() + i);
const isToday =
dayDate.getDate() === currentDay &&
dayDate.getMonth() === currentMonth &&
dayDate.getFullYear() === currentYear;
const dayNumber = dayDate.getMonth() === currentMonth
? dayDate.getDate()
: '-'; // 跨月日期显示为 '-'(可按需改为灰色数字)
const dayElement = document.createElement('div');
dayElement.className = isToday ? 'active' : '';
dayElement.innerHTML = `
<div>${daysOfWeek[i]}</div>
<div>${dayNumber}</div>
`;
daysContainer.appendChild(dayElement);
}
}
// 页面加载后立即渲染,并支持手动刷新
document.addEventListener('DOMContentLoaded', generateWeekDays);
// 可选:添加刷新按钮或定时更新
// setInterval(generateWeekDays, 60000); // 每分钟检查一次⚠️ 注意事项
- 跨月处理:代码通过 dayDate.getMonth() === currentMonth 判断是否属于当月,非当月日期显示 '-'(你也可替换为实际日期并添加 .other-month 类做样式区分);
- 时区安全:所有操作基于浏览器本地时区,若需 UTC 日历,需改用 getUTCDate() 等方法;
- 可访问性:建议为 .active 元素添加 aria-current="date" 属性;
- 性能优化:使用 innerHTML 批量插入比多次 appendChild 更高效,且避免了 Range.createContextualFragment 的兼容性顾虑(IE 不支持)。
此方案确保星期名称列严格对齐(daysOfWeek[i] 直接索引),日期动态精准,结构清晰易维护,可直接集成进任何现代前端项目。

















