构建日历表格需用 new date(year, month, 1).getday() 获取1号星期几,映射为周一为0后计算首行空格数;用 new date(year, month + 1, 0).getdate() 算当月天数;每个 设置 data-year/data-month/data-date 属性并用 getattribute 安全读取,创建日期后校验 isnan(date.gettime())。

用 table 构建日历表格结构时,如何正确处理首尾空白格
日历表格必须保证每周 7 列、行数固定为 6(最多 42 天),但每月天数不固定,且起始星期不固定。直接用 for 循环渲染日期会漏掉当月 1 号前、月末后空出来的格子。
关键不是“补多少”,而是“从哪天开始补”:先用 new Date(year, month, 1).getDay() 获取当月 1 号是周几(0 表示周日),再往前推 dayIndex 天作为第一格的日期值。注意:JavaScript 的 Date 里周日是 0,而多数日历头部按“周一至周日”排,需对齐逻辑。
- 若希望周一为每周首列,把
getDay()结果映射为(day + 6) % 7,让周一对应0 - 第一行要填的空格数 =
(firstDayOfWeek + 7 - firstWeekday) % 7,其中firstWeekday是你定义的每周起始日(如设为1表示周一) - 避免用字符串拼接生成
table,改用document.createElement('tr')+appendChild动态构建,方便后续绑定点击事件
计算某月总天数时,为什么不能硬写 31 或查表
二月天数随闰年变化,4 月、6 月等小月只有 30 天——硬编码会导致 2 月显示错乱或点击无响应。最简健壮方式是利用 Date 自动溢出特性:
function daysInMonth(year, month) {
return new Date(year, month + 1, 0).getDate();
}
原理:传入 month + 1(即下个月)和日期 0,JS 会自动回退到上个月最后一天。例如 new Date(2024, 2, 0) → 2024 年 2 月最后一天 → getDate() 返回 29。
- 注意月份参数是 0 起始:
0是一月,11是十二月 - 不要用
new Date(year, month, 32)向后推,某些浏览器在边界情况下可能返回异常日期对象 - 这个函数可安全用于所有年份,包括公元前或远期年份(只要在 JS 日期范围内)
点击日期单元格时,如何准确还原成真实 Date 对象
表格中每个 td 通常只存一个数字(如 15),但用户点击时需要知道这是哪年哪月的 15 号。不能依赖 DOM 文本内容解析,更不能靠闭包缓存当前年月——切换月份后闭包值就失效了。
推荐做法:给每个 td 设置 data-year、data-month、data-date 三个自定义属性,在事件处理器中读取:
cell.dataset.year = year;
cell.dataset.month = month; // 0-based
cell.dataset.date = day;
cell.addEventListener('click', () => {
const d = new Date(
+cell.dataset.year,
+cell.dataset.month,
+cell.dataset.date
);
console.log(d.toISOString().split('T')[0]); // 如 '2024-03-15'
});
- 避免用
innerHTML或textContent反推日期,用户可能复制粘贴导致内容污染 - 如果支持跨月显示(如上月尾/本月/下月头),需额外加
data-is-current-month="true"标识,防止选中灰色非本月日期 - 移动端要注意
touchstart和click冲突,建议统一用click并加cursor: pointer提升响应感
IE11 下 dataset 不可用?用 getAttribute 替代就行
IE11 支持 dataset,但仅限于符合驼峰命名规则的属性(如 data-fooBar → el.dataset.fooBar)。而 data-year 这种短横线写法在 IE11 中必须用 getAttribute('data-year') 才能取到值,否则返回 undefined。
所以兼容写法应统一使用 getAttribute,不依赖 dataset:
cell.setAttribute('data-year', year);
cell.setAttribute('data-month', month);
cell.setAttribute('data-date', day);
<p>cell.addEventListener('click', () => {
const y = parseInt(cell.getAttribute('data-year'), 10);
const m = parseInt(cell.getAttribute('data-month'), 10);
const d = parseInt(cell.getAttribute('data-date'), 10);
const clickedDate = new Date(y, m, d);
});</p>
- 别忘了
parseInt的第二个参数,否则字符串"08"会被当成八进制解析成8,而"09"直接变成NaN - 如果项目已用现代构建工具(如 Vite/Webpack),且不需支持 IE,可放心用
dataset,但上线前务必确认目标环境 - 真正容易被忽略的是:日期对象创建后没校验有效性,
new Date(2024, 13, 1)会静默变成2025-02-01,应加isNaN(clickedDate.getTime())判断
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











