基于React实现日历组件详细教程
前言
日历组件是常见的日期时间相关的组件,围绕日历组件设计师做出过各种尝试,展示的形式也是五花八门。但是对于前端开发者来讲,主要我们能够掌握核心思路,不管多么奇葩的设计我们都能够把它做出来。
本文将详细分析如何渲染一个简单的日历组件。
步骤
计算每个月中具体包含的日期
因为日历需要把当前月的每一天都展示出来,展示的前提是我们能够知道当前月具体都有哪些日子。那么如何优雅的获取每个月所有的天呢?
为了能够更方便的操作时间,我们需要引入dayjs 工具库,这也是我们手写日历组件唯一需要的工具库。
npm install dayjs
接下来我们实现一个工具方法,方法的目的是当我们传入年、月,就会返回当前月份的所有天。
import dayjs from "dayjs";export const getDaysOfMonth = (year: number, month: number) => {const firstDayOfMonth = dayjs(`${year}-${month}-1`);const lastDayOfMonth = dayjs(`${year}-${month + 1}-1`).subtract(1, "day");const days = [];let tempDate = firstDayOfMonth;while (tempDate.isBefore(lastDayOfMonth) || tempDate.isSame(lastDayOfMonth)) {days.push(tempDate);tempDate = tempDate.add(1, "day");}return days;
};
我们输出一下2023-08有哪些日子,并且简单渲染出来看看效果
function App() {const days = getDaysOfMonth(2023, 8);// 控制台打印days.forEach((day) => console.log(day.format("YYYY-MM-DD")));return (<div className="App">{days.map((day) => {return <div>{day.format('DD')}</div>;})}</div>);
}


以周为单位分组日期
- 首先我们先计算出日历分组标题,也就是周一,周二 … 周日
import dayjs from "dayjs";
import "dayjs/locale/zh-cn";
dayjs.locale("zh-cn");const weekTitles = useMemo(() => {return [...Array(7)].map((_, weekInx) => {return dayjs().day(weekInx);});}, []);// 日历标题渲染
<div className="calendar-title">{weekTitles.map((title) => {return <div>{title.format("ddd")}</div>;})}
</div>
- 对于当月所有的日期,每7天一组进行分组,也就是共分成7列
<div className="calendar-content">{days.map((day) => {return <div>{day.format("DD")}</div>;})}
</div>
- 加上对应的样式
.calendar {display: flex;flex-direction: column;width: 400px;
}.calendar-title {display: grid;grid-template-columns: repeat(7, 1fr);padding-bottom: 8px;
}.calendar-content {width: 100%;display: grid;grid-template-columns: repeat(7, 1fr);
}
- 看看效果

猛的一看好像完成了,但是仔细检查会发现,2023年8月1号是周二,我们渲染出来的却是周日。这肯定是不对的,那么问题出在哪儿呢?
由于我们是通过grid布局来渲染日期数组,数组的第一位数据是8月1号,所以就成了上面图中的效果。所以我们得想办法将每个月1号前的日期也补全直到每周周日。
让我们改造一下获取日期的工具方法getDaysOfMonth ,下面代码是最终改造完成后的。
export const getDaysOfMonth = (year: number, month: number) => {let firstDayOfMonth = dayjs(`${year}-${month}-1`);let lastDayOfMonth = dayjs(`${year}-${month + 1}-1`).subtract(1, "day");**// 开始补全第一天前的日期while (firstDayOfMonth.day() !== 0) {firstDayOfMonth = firstDayOfMonth.subtract(1, "day");}// 开始补全最后一天后的日期while (lastDayOfMonth.day() !== 6) {lastDayOfMonth = lastDayOfMonth.add(1, "day");}**const days = [];let tempDate = firstDayOfMonth;while (tempDate.isBefore(lastDayOfMonth) || tempDate.isSame(lastDayOfMonth)) {days.push(tempDate);tempDate = tempDate.add(1, "day");}return days;
};

可以看出我们已经正确的渲染出了日历,只是样式看起来比较简陋。
日历支持切换月份
上面的结果是我固定渲染了2023年8月的日历,大多数的日历是需要支持月份切换的,甚至有的日历设计是需要支持用户上下滚动就能够显示对应的月份。我们先简单实现通过按钮点击支持日历月份的切换。
- 显示当前月份(日历顶部显示档期月份)
// tsx
<div className="calendar-month"><div className="calendar-month-switch">{"<"}</div><div>{month.format("MMM YYYY")}</div><div className="calendar-month-switch">{">"}</div>
</div>// css
.calendar-month {display: flex;align-items: center;justify-content: space-between;padding: 16px;
}.calendar-month-switch {display: flex;align-items: center;justify-content: center;height: 24px;width: 24px;cursor: pointer;
}
简单看看效果

- 支持点击切换月份
从上图可以看到,月份两边有两个「箭头」按钮,接下来我们在这两个按钮上绑定事件,用来切换不同的月份
// 切换月份事件,-1 代表前一个月,1代表后一个月
const onMonthSwitch = (action: number) => {setMonth((month) => {return month.add(action, "month");});};<div className="calendar-month"><div className="calendar-month-switch" onClick={()=> onMonthSwitch(-1)}>{"<"} </div> <div>{month.format("MMM YYYY")}</div><div className="calendar-month-switch" onClick={()=> onMonthSwitch(1)}>{">"}</div>
</div>

小节总结
本文详细的记录了一个最简单的日历组件的实现过程,感兴趣但是之前还没有实现过日历的同学可以直接下载代码试试,希望对大家有所启发。也可以直接访问https://react-calendar-training.vercel.app/看成品效果。
由于设计师脑洞的千变万化,日历的展现形式也各不相同,后续我还将继续记录更多形式的日历实现过程,感兴趣的同学敬请期待。有任何问题请留言,如果对你有帮助,请帮忙点个赞🦉
相关链接
-
源码
https://github.com/levenx/react-calendar-training
-
在线DEMO效果
https://react-calendar-training.vercel.app
相关文章:
基于React实现日历组件详细教程
前言 日历组件是常见的日期时间相关的组件,围绕日历组件设计师做出过各种尝试,展示的形式也是五花八门。但是对于前端开发者来讲,主要我们能够掌握核心思路,不管多么奇葩的设计我们都能够把它做出来。 本文将详细分析如何渲染一…...
Web安全测试(二):HTTP状态码、响应和url详解
一、前言 结合内部资料,与安全渗透部门同事合力整理的安全测试相关资料教程,全方位涵盖电商、支付、金融、网络、数据库等领域的安全测试,覆盖Web、APP、中间件、内外网、Linux、Windows多个平台。学完后一定能成为安全大佬! 全部…...
什么是算法评价指标
在我们建立一个学习算法时,或者说训练一个模型时,我们总是希望最大化某一个给定的评价指标(比如说准确度Acc),但算法在学习过程中又会尝试优化某一个损失函数(比如说均方差MSE或者交叉熵Cross-entropy&…...
什么是软件压力测试?软件压力测试工具和流程有哪些?
软件压力测试 一、含义:软件压力测试是一种测试应用程序性能的方法,通过模拟大量用户并发访问,测试应用程序在压力情况下的表现和响应能力。软件压力测试的目的是发现系统潜在的问题,如内存泄漏、线程锁、资源泄漏等,…...
Wireshark流量分析例题
目录 前言 一、题目一(1.pcap) 二、题目二(2.pcap) 三、题目三(3.pcap) 四、题目四(4.pcap) 前言 Wireshark流量包分析对于安全来说是很重要的,我们可以通过Wireshark来诊断网络问题,检测网络攻击、监控网络流量以及捕获恶意软件等等 接下来我们…...
聚观早报|2023戴尔科技峰会助力创新;小米汽车电池供应商敲定
【聚观365】8月23日消息 2023戴尔科技峰会助力企业创新 小米汽车电池供应商敲定中创新航和宁德时代 iPhone15预计有6种配色 王小川卸任自动驾驶企业禾多科技董事 特斯拉动力总成副总裁宣布离职 2023戴尔科技峰会助力企业创新 近日“新生万物 数实新格局 —— 2023戴尔科技…...
大学生创业出路【第二弹】科创训练营
目录 🚀一、我从哪里了解到的训练营 🚀二、训练营里学习和日常 🔎学习 🔎环境和设备 🔎遇到的人 🔎团队记录视频 🚀三、感悟 个人主页:一天三顿-不喝奶茶Ἱ…...
EG3D: Efficient Geometry-aware 3D Generative Adversarial Networks [2022 CVPR]
长期以来,仅使用单视角二维照片集无监督生成高质量多视角一致图像和三维形状一直是一项挑战。现有的三维 GAN 要么计算密集,要么做出的近似值与三维不一致;前者限制了生成图像的质量和分辨率,后者则对多视角一致性和形状质量产生不…...
进行Stable Diffusion的ai训练怎么选择显卡?
Stable Diffusion主要用于从文本生成图像,是人工智能技术在内容创作行业中不断发展的应用。要在本地计算机上运行Stable Diffusion,您需要一个强大的 GPU 来满足其繁重的要求。强大的 GPU 可以让您更快地生成图像,而具有大量 VRAM 的更强大的…...
【Linux】【驱动】第一个相对完整的驱动编写
【Linux】【驱动】第一个相对完整的驱动编写 续1.驱动部分的代码2 app 代码3 操作相关的代码 续 这个章节会讲述去直接控制一个GPIO,高低电平。 因为linux不允许直接去操作寄存器,所以在操作寄存器的时候就需要使用到函数:ioremap 和iounma…...
PHP 高德地图,获取经纬度
function addresstolatlag($address){$abc "xxx学校(xx路店)";$key"24fb21b484f89f212dc3f4fd016e2b4d";//没有key$address $abc;$regeo_url"https://restapi.amap.com/v3/geocode/geo";$address_location$regeo_url."?outputJSON&a…...
Node基础--Node基础使用体验
在上一篇文章中提到我们按照好Node.js之后,就可以在控制台看到其版本。那么下面我们一起来看看如何使用node执行js文件代码。 (1).在本地创建一个名称为hello.js的文件,输入内容如下所示: console.log("helloworld");var a 1;var b 2;cons…...
22 从0到1:API测试怎么做?常用API测试工具简介
API 测试的基本步骤 准备测试数据(可选,不一定所有 API 测试都需要这一步);通过 API 测试工具,发起对被测 API 的 request;验证返回结果的 response。 Postman操作步骤 发起 API 调用;添加结…...
Skywalking Kafka Tracing实现
背景 Skywalking默认场景下,Tracing对于消息队列的发送场景,无法将TraceId传递到下游消费者,但对于微服务场景下,是有大量消息队列的业务场景的,这显然无法满足业务预期。 解决方案 Skywalking的官方社区中…...
Perl 解析字符串为日期对象并获取多天前的日期字符串
Perl 解析字符串 perl语言中的库 Time::Piece可以将字符串解析为日期对象。 use Time::Piece; my ($y, $m, $d) 20230823 ~ /^([0-9]{4})([0-9]{2})([0-9]{2})\z/ or die;my $dt Time::Piece->strptime("$y$m$d","%Y%m%d");Perl获取多天之前的日期 …...
C语言问题 - 关于一维数组和二维数组用*a+i形式表达
问题 今天在编写程序时被一个语句搞懵了: #include<stdio.h>int main() {int *pa[6];int a[2][3] {{1,2,3},{4,5,6}};int sum 0;int i,j,k 0;for (i0; i<2; i){for (j0; j<3; j){*(pa k) *(a i) j;k;}}for (i0; i<k; i){printf("%d &q…...
验证码识别DLL ,滑块识别SDK,OCR图片转文字,机器视觉找物品
验证码识别DLL ,滑块识别SDK 你们用过哪些OCR提取文字,识图DLL,比如Opencv,Labview机器视觉找物品之类?...
【图论】最小生成树的应用
一.题目 P1550 [USACO08OCT] Watering Hole G - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 二.分析 1.我们是要使所有的农场都要有水 2.可以从起点引水,也可以互相引水。 3.费用要最小 这时我们可以想到最小生成树,建立一个虚拟节点即可。思路一…...
C++类模板的特化(三)
本文主要介绍类模板的特化、局部特化和缺省模板实参; 1.类模板的特化 类模板的特化(Class Template Specialization)是指为特定的模板参数提供自定义实现的过程。通过特化,我们可以针对某些特定的类型或条件提供不同的行为或实现…...
基于YOLOV8模型的课堂场景下人脸目标检测系统(PyTorch+Pyside6+YOLOv8模型)
摘要:基于YOLOV8模型的课堂场景下人脸目标检测系统可用于日常生活中检测与定位课堂场景下人脸,利用深度学习算法可实现图片、视频、摄像头等方式的目标检测,另外本系统还支持图片、视频等格式的结果可视化与结果导出。本系统采用YOLOv8目标检…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...
从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...
vue3 daterange正则踩坑
<el-form-item label"空置时间" prop"vacantTime"> <el-date-picker v-model"form.vacantTime" type"daterange" start-placeholder"开始日期" end-placeholder"结束日期" clearable :editable"fal…...
02.运算符
目录 什么是运算符 算术运算符 1.基本四则运算符 2.增量运算符 3.自增/自减运算符 关系运算符 逻辑运算符 &&:逻辑与 ||:逻辑或 !:逻辑非 短路求值 位运算符 按位与&: 按位或 | 按位取反~ …...
leetcode_69.x的平方根
题目如下 : 看到题 ,我们最原始的想法就是暴力解决: for(long long i 0;i<INT_MAX;i){if(i*ix){return i;}else if((i*i>x)&&((i-1)*(i-1)<x)){return i-1;}}我们直接开始遍历,我们是整数的平方根,所以我们分两…...
[特殊字符] Spring Boot底层原理深度解析与高级面试题精析
一、Spring Boot底层原理详解 Spring Boot的核心设计哲学是约定优于配置和自动装配,通过简化传统Spring应用的初始化和配置流程,显著提升开发效率。其底层原理可拆解为以下核心机制: 自动装配(Auto-Configuration) 核…...
篇章一 论坛系统——前置知识
目录 1.软件开发 1.1 软件的生命周期 1.2 面向对象 1.3 CS、BS架构 1.CS架构编辑 2.BS架构 1.4 软件需求 1.需求分类 2.需求获取 1.5 需求分析 1. 工作内容 1.6 面向对象分析 1.OOA的任务 2.统一建模语言UML 3. 用例模型 3.1 用例图的元素 3.2 建立用例模型 …...
Heygem50系显卡合成的视频声音杂音模糊解决方案
如果你在使用50系显卡有杂音的情况,可能还是官方适配问题,可以使用以下方案进行解决: 方案一:剪映替换音色(简单适合普通玩家) 使用剪映换音色即可,口型还是对上的,没有剪映vip的&…...
大模型的LoRa通讯详解与实现教程
一、LoRa通讯技术概述 LoRa(Long Range)是一种低功耗广域网(LPWAN)通信技术,由Semtech公司开发,特别适合于物联网设备的长距离、低功耗通信需求。LoRa技术基于扩频调制技术,能够在保持低功耗的同时实现数公里甚至数十公里的通信距离。 LoRa的主要特点 长距离通信:在城…...
