如何用Flex布局实现日历每月日期的7天换行排列?
问题解决:日历日期块每行7个自动换行
问题描述
制作了展示全年12个月所有日期的日历,当前日期块无法自适应换行,希望实现每行仅显示7个日期块以达到真实日历样式,询问需通过CSS解决还是调整逻辑层面。当前效果如下:

当前代码:
<script lang="ts"> const weekNames = ['Sun', 'Mon', 'Tue', 'Wed', 'Thurs', 'Fri', 'Sat']; const months = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; let daysInMonth: Array<string> = []; let dayNumberArray: Array<number> = []; let days: Array<Date> = []; const getDaysInMonth = (month: number, year: number) => { // 创建日期对象 let date = new Date(year, month); // 遍历当月所有日期 while (date.getMonth() === month) { days.push(new Date(date)); date.setDate(date.getDate() + 1); } for (let i = 0; i < daysInMonth.length; i++) { dayNumberArray.push(i); } }; // 遍历所有月份生成日期 months.forEach((m) => { getDaysInMonth(m - 1, 2023); }); const getDaysInYear = (year: number) => { let daysInYear = checkLeapYear(year) ? 366 : 365; }; const checkLeapYear = (year: number) => { return year % 400 === 0 || (year % 100 !== 0 && year % 4 === 0); }; </script> <main> <section class="cal"> <div class="cal-header"> <h1>Calendar</h1> </div> <div class="cal-week"> {#each weekNames as week} <div class="cal-weekday"> {week} </div> {/each} </div> <div class="cal-month"> {#each days as day} {#if day} <div class="cal-day"> <div class="cal-num"> {day.getDate()} </div> </div> {/if} {/each} </div> </section> </main> <style> * { margin: 0; padding: 0; box-sizing: border-box; } .cal { width: 100%; height: 100%; font-family: 'Poppins'; overflow-y: scroll; border: 1px solid black; } .cal-header { display: flex; justify-content: center; border: 1px solid black; } .cal-week { display: flex; border: 1px solid black; background-color: rgb(146, 216, 183); } .cal-weekday { display: flex; justify-content: center; width: 100%; } .cal-month { display: flex; flex-wrap: wrap; width: 100%; height: auto; border: 1px solid black; } .cal-day { font-size: 28px; font-weight: bold; border-radius: 8px; min-width: 100px; line-height: 100px; height: 100px; text-align: center; margin: 5px; border: 1px solid black; } .cal-day:hover { background-color: rgb(230, 229, 229); } .cal-num { font-size: 1.5rem; padding: 0.15rem; } </style>
解决方案
要实现真实日历的布局,CSS和逻辑层面都需要调整:
1. CSS层面:强制每行7个日期块
当前.cal-day的min-width:100px无法保证每行刚好7个,修改样式让每个日期块宽度自适应容器,占1/7宽度(减去左右margin):
.cal-day { font-size: 28px; font-weight: bold; border-radius: 8px; /* 替换固定最小宽度为自适应宽度 */ width: calc(100% / 7 - 10px); line-height: 100px; height: 100px; text-align: center; margin: 5px; border: 1px solid black; }
给日期容器添加上下内边距,避免日期块贴边:
.cal-month { display: flex; flex-wrap: wrap; width: 100%; height: auto; border: 1px solid black; padding: 5px 0; }
设置后,flex-wrap:wrap会自动让每行排列7个日期块,超出后换行。
2. 逻辑层面:补全每月开头的空白日期
真实日历中每月第一天不一定是周日,需要在每月日期前添加对应数量的空白块,确保日期与星期头对齐。修改getDaysInMonth函数:
const getDaysInMonth = (month: number, year: number) => { let date = new Date(year, month); // 获取当月第一天的星期数(0=周日,6=周六) const firstDayWeek = date.getDay(); // 添加对应数量的空白块 for(let i=0; i<firstDayWeek; i++){ days.push(null); // 用null标记空白块 } while (date.getMonth() === month) { days.push(new Date(date)); date.setDate(date.getDate() + 1); } };
在模板中处理空白块,添加专属样式区分:
<div class="cal-month"> {#each days as day} {#if day} <div class="cal-day"> <div class="cal-num"> {day.getDate()} </div> </div> {:else} <!-- 空白日期块,隐藏边框和背景 --> <div class="cal-day cal-day-empty"></div> {/if} {/each} </div>
添加空白日期的样式:
.cal-day-empty { border: none; background: transparent; pointer-events: none; /* 禁止点击交互 */ }
进阶优化:按月份拆分布局
当前代码将全年日期放在一个容器内,建议按月份拆分,每个月份独立展示:
- 修改脚本,按月份分组存储日期:
// 替换原days数组为二维数组,每个子数组对应一个月的日期(含空白块) let monthsDays: Array<Array<Date | null>> = []; const getDaysInMonth = (month: number, year: number) => { const monthDays: Array<Date | null> = []; let date = new Date(year, month); const firstDayWeek = date.getDay(); for(let i=0; i<firstDayWeek; i++){ monthDays.push(null); } while (date.getMonth() === month) { monthDays.push(new Date(date)); date.setDate(date.getDate() + 1); } monthsDays.push(monthDays); }; // 初始化每个月的日期 months.forEach((m) => { getDaysInMonth(m - 1, 2023); });
- 修改模板,按月份遍历展示:
<div class="cal"> <div class="cal-header"> <h1>Calendar</h1> </div> {#each monthsDays as monthDays, index} <div class="cal-month"> <h2>{index + 1}月</h2> <div class="cal-week"> {#each weekNames as week} <div class="cal-weekday"> {week} </div> {/each} </div> <div class="cal-days"> {#each monthDays as day} {#if day} <div class="cal-day"> <div class="cal-num"> {day.getDate()} </div> </div> {:else} <div class="cal-day cal-day-empty"></div> {/if} {/each} </div> </div> {/each} </div>
- 调整对应样式:
.cal-days { display: flex; flex-wrap: wrap; width: 100%; padding: 5px 0; }
内容的提问来源于stack exchange,提问作者lache
相关产品推荐
相关产品推荐

