You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Flex布局实现日历每月日期的7天换行排列?

问题解决:日历日期块每行7个自动换行

问题描述

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

calendar效果

当前代码:

<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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 12:45:00