用 JavaScript 动态创建日历表格:createCalendar 实战解析(zh.javascript.info 经典任务) 文档教程前端【免费下载链接】zh.javascript.info现代 JavaScript 教程The Modern JavaScript Tutorial以最新的 ECMAScript 规范为基准通过简单但足够详细的内容为你讲解从基础到高阶的 JavaScript 相关知识。项目地址https://gitcode.com/gh_mirrors/zh/zh.javascript.info点击查看免费下载本篇文章以 zh.javascript.info 中「修改文档document」章节的经典任务「创建一个日历」为核心完整讲解createCalendar(elem, year, month)函数的实现思路、JavaScript 日期对象的正确用法以及通过innerHTML字符串拼接动态生成table的完整方案。读完本文你将掌握如何利用Date对象处理「月份从 0 开始」「每周从星期一开始」等日历排版的经典陷阱以及如何用一条 HTML 字符串干净地生成整张月历表格。任务背景它来自哪个章节该任务位于教程「修改文档document」小节07-modifying-document/article.md的练习区。在阅读本任务前你已经掌握了该章节的核心知识用document.createElement(tag)创建元素节点、用document.createTextNode(text)创建文本节点用node.append / prepend / before / after / replaceWith / remove等现代方法插入和移除节点用elem.insertAdjacentHTML(where, html)把 HTML 字符串按四个位置beforebegin、afterbegin、beforeend、afterend插入用elem.innerHTML一次性写入整段 HTML。「创建日历」这个任务本质上是把这些 DOM 修改能力与 JavaScript 日期计算结合起来的综合练习它不要求任何点击交互只要求根据给定的year和month在页面元素中生成一张结构正确的月历表格。任务要求原文编写一个函数createCalendar(elem, year, month)对该函数的调用应该使用给定的year/month创建一个日历并将创建的日历放入elem中创建的日历应该是一个表格table其中每一周用tr表示每一天用td表示表格顶部应该是带有星期名的th第一天应该是 Monday星期一依此类推直到 Sunday星期日例如createCalendar(cal, 2012, 9)应该在元素cal中生成对应的 2012 年 9 月日历附加说明本任务只要求生成日历不需要点击交互功能。任务对应的起始模板位于 source.view/index.html其中已经提供了div idcalendar/div占位容器和样式以及一个待你填充的函数骨架div idcalendar/div script function createCalendar(elem, year, month) { // ...your code that generates the calendar in elem... } createCalendar(calendar, 2012, 9); /script解决方案用一条 HTML 字符串构建整张表格官方解答见 solution.md 与 solution.view/index.html采用了一个非常简洁的策略我们将表格创建为字符串table.../table然后将其赋值给innerHTML。也就是说不逐格调用createElement/append来搭建 DOM 树而是先在内存中把整张表格的 HTML 拼成一条字符串最后一次性赋值给elem.innerHTML。对于这种结构规整、内容以日期数字为主的表格字符串拼接方式代码更短、可读性更好也省去了大量重复的 DOM 操作调用。核心算法五步官方解答将整个算法拆解为 5 步使用th创建带有星期名的表头创建日期对象d new Date(year, month-1)。它是month的第一天考虑到 JavaScript 中的月份从0开始而不是从1开始直到月份的第一天d.getDay()前面的几个单元格是空的。用td/td填充它们天数增长dd.setDate(d.getDate()1)。如果d.getMonth()还没到下一个月就将新的单元格td添加到日历中如果那天是星期日就添加新行/trtr如果该月结束但表格的行尚未填满就用空的td补齐。完整参考实现function createCalendar(elem, year, month) { let mon month - 1; // JS 中月份是 0..11而不是 1..12 let d new Date(year, mon); let table tabletrthMO/ththTU/ththWE/ththTH/ththFR/ththSA/ththSU/th/trtr; // 第一行的空格 // 从星期一 到 这个月的第一天 // * * * 1 2 3 4 for (let i 0; i getDay(d); i) { table td/td; } // 填充有实际日期的 td while (d.getMonth() mon) { table td d.getDate() /td; if (getDay(d) % 7 6) { // 星期日一周最后一天 - 换行 table /trtr; } d.setDate(d.getDate() 1); } // 补上月末之后剩余的空格填满最后一行 // 29 30 31 * * * * if (getDay(d) ! 0) { for (let i getDay(d); i 7; i) { table td/td; } } // 关闭表格 table /tr/table; elem.innerHTML table; } function getDay(date) { // 获取星期编号从 0星期一到 6星期日 let day date.getDay(); if (day 0) day 7; // 让星期日0变成最后一天 return day - 1; } createCalendar(calendar, 2012, 9);以createCalendar(calendar, 2012, 9)为例这段代码生成的 2012 年 9 月日历布局如下该月 1 号是星期六因此第一行以两个空格开头30 号是星期日因此最后一行恰好以 30 收尾无需补空格MO TU WE TH FR SA SU 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30配套样式渲染出的表格是否美观取决于 CSS。仓库给出的 solution.view/index.html 中提供了配套样式可以直接复用table { border-collapse: collapse; } td, th { border: 1px solid black; padding: 3px; text-align: center; } th { font-weight: bold; background-color: #E6E6E6; }其中border-collapse: collapse让相邻单元格的边框合并为一条线th用灰色背景加粗区分表头td居中对齐日期数字。关键知识点拆解为什么month要减 1JavaScript 的Date对象中月份是从0开始计数的0代表一月11代表十二月。因此当用户传入的month是「112」的自然月编号时必须执行mon month - 1再传给new Date(year, mon)。这是本任务最容易踩的第一个坑官方解答中专门用注释强调了这一点。关于Date对象的构造与常用方法可以复习教程 日期和时间Date 章节。为什么每周从星期一开始需要重写 getDay原生Date.prototype.getDay()返回0星期日到6星期六也就是一周从星期日开始。而本任务要求日历以星期一开始星期日在最后。官方的getDay(date)辅助函数完成了一次坐标转换function getDay(date) { // 从 0星期一到 6星期日 let day date.getDay(); if (day 0) day 7; // 星期日0变成 7即最后一天 return day - 1; // 整体左移一位 }转换结果星期一 →0星期二 →1……星期六 →5星期日 →6。这样一来月初第一天是星期几就决定了第一行前面要放几个空格单元格for (let i 0; i getDay(d); i)星期日的编号是6所以getDay(d) % 7 6可以判断「是否到了该换行的时候」。这里的% 7写法让判断在逻辑上更通用等价于getDay(d) 6。遍历整个月setDate 自增与 getMonth 边界判断生成日期单元格的核心是一个while循环while (d.getMonth() mon) { table td d.getDate() /td; if (getDay(d) % 7 6) { table /trtr; } d.setDate(d.getDate() 1); }d.setDate(d.getDate() 1)是 JavaScript 中「日期加一天」的标准写法。它的巧妙之处在于当日期越过当月边界时例如 9 月 30 日 1Date对象会自动进位到下个月的 1 号因此d.getMonth()会变成mon 1循环条件d.getMonth() mon自然失效循环随之终止——不需要手动计算每月有多少天。循环结束后d恰好指向下个月的 1 号此时getDay(d)的值恰好等于「本月最后一天之后剩余的空格数」因此最后一行补空格的逻辑可以直接复用if (getDay(d) ! 0) { for (let i getDay(d); i 7; i) { table td/td; } }这个设计非常精妙不需要额外保存任何状态循环退出时d本身携带的星期信息就足够补齐最后一行了。为什么用 innerHTML 而不是 DOM 方法逐个插入在 07-modifying-document/article.md 章节中你学到了多种插入节点的方法append、prepend、insertAdjacentHTML等。本任务选择innerHTML而非逐个createElementappend理由很实际代码量更少整张表格只需一条字符串拼接循环不需要为每个td单独创建节点结构一目了然字符串中的tr/td层级关系直接映射最终表格结构便于阅读和调试性能足够对一张月历这样的小型静态结构一次性赋值innerHTML比几十次 DOM 插入调用更高效。当然如果你希望代码风格更贴近「DOM 操作」教学点也可以用document.createElement(table)配合append逐行逐格构建两种方式都能通过本任务只是官方解答选择了更简洁的字符串方案。验证与运行方式仓库为本题提供了两个可直接运行的页面source.view/index.html任务起始模板函数体为空solution.view/index.html完整解答打开即可看到 2012 年 9 月的日历渲染结果。验证建议将createCalendar(calendar, 2012, 9)中的参数替换为其他年份/月份组合重点检查三类边界情况月初是星期日如 2012 年 1 月第一行不应出现空格单元格直接从 1 号开始月末不落在星期日如 2012 年 9 月之外的其他月份最后一行应有正确的空格补齐保证整张表格行数完整二月平年/闰年如 2011 年 2 月 28 天、2012 年 2 月 29 天验证while循环边界判断是否正确终止。总结「创建日历」是 DOM 修改章节的综合性练习它把三个关键能力串联在一起日期计算new Date(year, month - 1)处理月份偏移setDate(getDate() 1)自动跨月getMonth()判断月界星期坐标转换用getDay辅助函数把原生「星期日开头」的编号改造成「星期一开头」并据此计算行首空格与换行时机表格字符串生成用一条table.../table字符串配合innerHTML一次性写入兼顾简洁与性能。掌握这套模式后你可以轻松扩展出带周数、节假日高亮、前后月切换等交互功能的日历组件——但正如任务所说先让一张静态月历正确渲染出来是一切扩展的地基。赞分享文档教程前端【免费下载链接】zh.javascript.info现代 JavaScript 教程The Modern JavaScript Tutorial以最新的 ECMAScript 规范为基准通过简单但足够详细的内容为你讲解从基础到高阶的 JavaScript 相关知识。项目地址https://gitcode.com/gh_mirrors/zh/zh.javascript.info点击查看免费下载相关推荐使用 JavaScript 生成月份日历表格createCalendar 实战解析Modern JavaScript Tutorial使用 JavaScript 生成月份日历表格createCalendar 实战解析Modern JavaScript Tutorial 导读 本文围绕 M文档/教程前端JavaScript.info 实战用 innerHTML 与 Date 对象编写动态日历表格createCalendar 全解析JavaScript.info 实战用 innerHTML 与 Date 对象编写动态日历表格createCalendar 全解析 本篇文章基于《现代 J文档教程前端事件委托实战用 30 行代码实现可排序表格zh.javascript.info 教程任务解析事件委托实战用 30 行代码实现可排序表格zh.javascript.info 教程任务解析 导读 本文基于《现代 JavaScript 教程》zh.j文档教程前端上一篇ARIS 专利撰写系列USPTO 美国专利申请格式指南Claims / Specification / Drawings / IDS 全解析下一篇kkFileView CAD图纸参数提取技术架构与系统设计深度解析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考