
本文教你用纯 javascript 实现一个始终显示连续7天(从周一到周日)、星期名位置固定、日期数字动态更新的响应式周历,解决原代码中索引错乱、未覆盖全周、年月跨月逻辑缺失等问题。
本文教你用纯 javascript 实现一个始终显示连续7天(从周一到周日)、星期名位置固定、日期数字动态更新的响应式周历,解决原代码中索引错乱、未覆盖全周、年月跨月逻辑缺失等问题。
要实现一个“七天固定布局”的周历(即 Ma 至 Zo 七个列位置恒定,仅日期数字随当前周变化),关键在于:确保每周始终从周一(Ma)开始,并正确处理跨月、跨年边界。原代码存在多个核心问题:
- 循环仅执行 i
- 使用 today.getDate() + i 计算日期,未考虑月末/月初翻页(如1月31日+1会变成2月1日,但未更新显示逻辑);
- 星期名顺序与日期未对齐(getDay() 返回 0=Sunday,但数组以 Ma(Monday)开头,需偏移校准);
- 未处理非当前月份的日期(应显示为 - 或灰显,而非错误数字);
- console.log 无输出,说明函数可能未执行(如 DOM 元素 ID 不匹配或脚本执行过早)。
以下是优化后的完整实现(含 HTML、CSS、JS):
<div id="calendar"> <p>Month & year values</p><div class="aritcle_card flexRow artxards"> <div class="artcardd flexRow"> <a class="aritcle_card_img" rel="nofollow" href="/ai/2903" title="OpenCLI Tool Integration"><img src="https://img.php.cn/upload/ai_manual/001/246/273/177985655419071.png" alt="OpenCLI Tool Integration" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a> <div class="aritcle_card_info flexColumn"> <a rel="nofollow" href="/ai/2903" title="OpenCLI Tool Integration" class="overflowclass">OpenCLI Tool Integration</a> <p class="overflowclass">一款AI开发辅助工具,主要用于使用 OpenCLI 工具,可从各类网站及桌面应用中提取数据、下载媒体内容、控制外部 CLI 工具。支持 Bilibili、知乎、小红书、Twitter/X、Reddit、YouTube、Boss直聘、即刻、微博等 30+ 个平台,以及 Cursor、Codex、ChatGPT、Notion 等桌面应用。当用户需要:从社...,适合需要提升相关任务效率的用户。</p> </div> <a rel="nofollow" href="/ai/2903" title="OpenCLI Tool Integration" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a> </div> </div> <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.5em 0 0.25em;
}
#calendar > div {
display: flex;
flex-direction: row;
justify-content: space-around;
padding: 0.25em 0;
}
#calendar > div > div {
background-color: #e6f7ff;
text-align: center;
width: 3rem;
border-radius: 4px;
padding: 0.3em 0;
}
#calendar > div > div > div:first-of-type {
font-style: italic;
color: #555;
font-size: 0.9em;
margin-bottom: 0.2em;
}
#calendar > div > div > div:last-of-type {
font-weight: 600;
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();
// 调整日期:将 today 设为本周一(ISO week start)
const monday = new Date(today);
monday.setDate(today.getDate() - ((today.getDay() + 6) % 7)); // getDay(): 0=Sun → 6=Sat → -6 → Mon
// 更新标题:显示当前周所在月份及年份(如 "Maart - 2024")
const weekMonth = monday.getMonth();
const weekYear = monday.getFullYear();
monthElement.textContent = `${monthNames[weekMonth]} - ${weekYear}`;
// 清空容器
daysContainer.innerHTML = '';
// 渲染7天:从周一(monday)开始逐日递增
for (let i = 0; i ${daysOfWeek[i]}
<div>${dayNum}</div>
`;
daysContainer.appendChild(dayEl);
}
}
// 确保 DOM 加载完成后再执行
document.addEventListener('DOMContentLoaded', generateWeekDays);
✅ 关键改进点说明:
- ✅ 严格7天循环:for (let i = 0; i
- ✅ 周一基准定位:通过 ((today.getDay() + 6) % 7) 将 Sunday(0) → Monday(1) 对齐,精准回退到本周一;
- ✅ 跨月智能处理:仅当 dayDate.getMonth() === currentMonth 时显示真实日期,否则显示 '-';
- ✅ 今日高亮精准:同时比对 date、month、year,避免同日不同月误判;
- ✅ DOM 安全执行:使用 DOMContentLoaded 替代 window.onload,避免元素未就绪导致 null 错误;
- ✅ 语义化结构:HTML 结构清晰,CSS 使用现代属性(如 ch 单位、:first-of-type),便于维护与主题定制。
? 扩展提示:如需支持左右翻页(上/下周),可封装 monday 为状态变量,添加 prevWeek() / nextWeek() 方法并重绘;若需国际化,可将 daysOfWeek 和 monthNames 提取为配置对象,按 navigator.language 动态加载。
该方案轻量、无依赖、兼容主流浏览器,可直接集成进任何现代前端项目。










