生成日历table时需手动计算起始空白列数,用双重循环填充日期并控制换行,日期比对应转字符串避免引用错误,配合table-layout: fixed和均分宽度实现响应式布局。

用 table 生成基础日历结构时,别硬塞7列头
直接写 <tr>
<th>日</th>
<th>一</th>...</tr> 没问题,但要注意:星期几的顺序必须和实际日历对齐(比如周日为第1列,就别按「周一到周日」排)。浏览器不会自动帮你校准起始日,table 只负责渲染,逻辑得自己算。
常见错误是把当月1号当天的 weekday 值(getDay() 返回 0–6)当成列索引直接用,结果日历从周三开始却还在第一列塞1号——这会导致整行错位。正确做法是用空白 <td></td> 填满前导空格:
let firstDay = new Date(year, month, 1).getDay(); // 周日=0,周六=6 let padCells = firstDay === 0 ? 6 : firstDay - 1; // 若周日为第一天,需补6个空格
填充日期单元格时,避免用 for (let i = 1; i 硬循环
单纯遍历天数会忽略跨行问题:比如某月有31天,从周二开始,第7天(周日)后该换行,但硬循环不感知行边界,容易把所有日期塞进同一行或漏掉换行。
更稳妥的方式是用双重循环:外层控制行(最多6行),内层填7列,再用计数器判断是否已填完当月所有日期:
- 初始化
date = 1 - 每行循环7次,每次检查
date ,满足则输出 <code><td>${date++}</td>,否则输出空<td></td> - 外层循环最多跑6次,防止2月只28天却留出多余行
给当天加样式要用 new Date().toDateString() 对比,别比 Date 对象引用
很多人写 if (dateObj === today),结果永远不生效——因为每次 new 出来的 Date 对象内存地址不同。正确做法是转成字符串比较:
const todayStr = new Date().toDateString();
// 渲染每个日期时:
const cellDate = new Date(year, month, day);
if (cellDate.toDateString() === todayStr) {
td.className = 'today';
}
注意:toDateString() 返回类似 "Mon Apr 01 2024",精确到日,不含时分秒,适合做等值判断。用 toISOString().split('T')[0] 也行,但多一次字符串分割,没必要。
响应式塌陷时,table-layout: fixed 比默认值更可控
小屏下表格容易横向溢出或列宽崩坏。默认 table-layout: auto 会让浏览器按内容撑开列宽,而日历每列宽度应均等。强制设 table-layout: fixed 后,配合 width: 100% 和 th, td { width: 14.2857% }(100% ÷ 7),能稳住列宽。
但要注意:如果某列内容超长(比如加了事件标签),fixed 模式下文本不会自动换行,得额外加 word-break: break-word 或限制 font-size。
真正麻烦的是跨设备交互——手机上点选某天,td 点击热区太小,得用 padding 扩展,但又不能让表格撑开。建议统一设 td, th { padding: 0.5em; box-sizing: border-box; },避免内边距影响宽度计算。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











