当前位置: 首页 > news >正文

基于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>);
}

在这里插入图片描述
在这里插入图片描述

以周为单位分组日期

  1. 首先我们先计算出日历分组标题,也就是周一,周二 … 周日
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>
  1. 对于当月所有的日期,每7天一组进行分组,也就是共分成7列
<div className="calendar-content">{days.map((day) => {return <div>{day.format("DD")}</div>;})}
</div>
  1. 加上对应的样式
.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);
}
  1. 看看效果
    在这里插入图片描述

猛的一看好像完成了,但是仔细检查会发现,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月的日历,大多数的日历是需要支持月份切换的,甚至有的日历设计是需要支持用户上下滚动就能够显示对应的月份。我们先简单实现通过按钮点击支持日历月份的切换。

  1. 显示当前月份(日历顶部显示档期月份)
// 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 代表前一个月,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/看成品效果。

由于设计师脑洞的千变万化,日历的展现形式也各不相同,后续我还将继续记录更多形式的日历实现过程,感兴趣的同学敬请期待。有任何问题请留言,如果对你有帮助,请帮忙点个赞🦉

相关链接

  1. 源码

    https://github.com/levenx/react-calendar-training

  2. 在线DEMO效果

    https://react-calendar-training.vercel.app

相关文章:

基于React实现日历组件详细教程

前言 日历组件是常见的日期时间相关的组件&#xff0c;围绕日历组件设计师做出过各种尝试&#xff0c;展示的形式也是五花八门。但是对于前端开发者来讲&#xff0c;主要我们能够掌握核心思路&#xff0c;不管多么奇葩的设计我们都能够把它做出来。 本文将详细分析如何渲染一…...

Web安全测试(二):HTTP状态码、响应和url详解

一、前言 结合内部资料&#xff0c;与安全渗透部门同事合力整理的安全测试相关资料教程&#xff0c;全方位涵盖电商、支付、金融、网络、数据库等领域的安全测试&#xff0c;覆盖Web、APP、中间件、内外网、Linux、Windows多个平台。学完后一定能成为安全大佬&#xff01; 全部…...

什么是算法评价指标

在我们建立一个学习算法时&#xff0c;或者说训练一个模型时&#xff0c;我们总是希望最大化某一个给定的评价指标&#xff08;比如说准确度Acc&#xff09;&#xff0c;但算法在学习过程中又会尝试优化某一个损失函数&#xff08;比如说均方差MSE或者交叉熵Cross-entropy&…...

什么是软件压力测试?软件压力测试工具和流程有哪些?

软件压力测试 一、含义&#xff1a;软件压力测试是一种测试应用程序性能的方法&#xff0c;通过模拟大量用户并发访问&#xff0c;测试应用程序在压力情况下的表现和响应能力。软件压力测试的目的是发现系统潜在的问题&#xff0c;如内存泄漏、线程锁、资源泄漏等&#xff0c;…...

Wireshark流量分析例题

目录 前言 一、题目一(1.pcap) 二、题目二(2.pcap) 三、题目三(3.pcap) 四、题目四(4.pcap) 前言 Wireshark流量包分析对于安全来说是很重要的&#xff0c;我们可以通过Wireshark来诊断网络问题&#xff0c;检测网络攻击、监控网络流量以及捕获恶意软件等等 接下来我们…...

聚观早报|2023戴尔科技峰会助力创新;小米汽车电池供应商敲定

【聚观365】8月23日消息 2023戴尔科技峰会助力企业创新 小米汽车电池供应商敲定中创新航和宁德时代 iPhone15预计有6种配色 王小川卸任自动驾驶企业禾多科技董事 特斯拉动力总成副总裁宣布离职 2023戴尔科技峰会助力企业创新 近日“新生万物 数实新格局 —— 2023戴尔科技…...

大学生创业出路【第二弹】科创训练营

目录 &#x1f680;一、我从哪里了解到的训练营 &#x1f680;二、训练营里学习和日常 &#x1f50e;学习 &#x1f50e;环境和设备 &#x1f50e;遇到的人 &#x1f50e;团队记录视频 &#x1f680;三、感悟 ​​​​个人主页&#xff1a;一天三顿-不喝奶茶&#x1f39…...

EG3D: Efficient Geometry-aware 3D Generative Adversarial Networks [2022 CVPR]

长期以来&#xff0c;仅使用单视角二维照片集无监督生成高质量多视角一致图像和三维形状一直是一项挑战。现有的三维 GAN 要么计算密集&#xff0c;要么做出的近似值与三维不一致&#xff1b;前者限制了生成图像的质量和分辨率&#xff0c;后者则对多视角一致性和形状质量产生不…...

进行Stable Diffusion的ai训练怎么选择显卡?

Stable Diffusion主要用于从文本生成图像&#xff0c;是人工智能技术在内容创作行业中不断发展的应用。要在本地计算机上运行Stable Diffusion&#xff0c;您需要一个强大的 GPU 来满足其繁重的要求。强大的 GPU 可以让您更快地生成图像&#xff0c;而具有大量 VRAM 的更强大的…...

【Linux】【驱动】第一个相对完整的驱动编写

【Linux】【驱动】第一个相对完整的驱动编写 续1.驱动部分的代码2 app 代码3 操作相关的代码 续 这个章节会讲述去直接控制一个GPIO&#xff0c;高低电平。 因为linux不允许直接去操作寄存器&#xff0c;所以在操作寄存器的时候就需要使用到函数&#xff1a;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之后&#xff0c;就可以在控制台看到其版本。那么下面我们一起来看看如何使用node执行js文件代码。 (1).在本地创建一个名称为hello.js的文件&#xff0c;输入内容如下所示: console.log("helloworld");var a 1;var b 2;cons…...

22 从0到1:API测试怎么做?常用API测试工具简介

API 测试的基本步骤 准备测试数据&#xff08;可选&#xff0c;不一定所有 API 测试都需要这一步&#xff09;&#xff1b;通过 API 测试工具&#xff0c;发起对被测 API 的 request&#xff1b;验证返回结果的 response。 Postman操作步骤 发起 API 调用&#xff1b;添加结…...

Skywalking Kafka Tracing实现

背景 Skywalking默认场景下&#xff0c;Tracing对于消息队列的发送场景&#xff0c;无法将TraceId传递到下游消费者&#xff0c;但对于微服务场景下&#xff0c;是有大量消息队列的业务场景的&#xff0c;这显然无法满足业务预期。 解决方案 Skywalking的官方社区中&#xf…...

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形式表达

问题 今天在编写程序时被一个语句搞懵了&#xff1a; #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提取文字&#xff0c;识图DLL&#xff0c;比如Opencv,Labview机器视觉找物品之类&#xff1f;...

【图论】最小生成树的应用

一.题目 P1550 [USACO08OCT] Watering Hole G - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 二.分析 1.我们是要使所有的农场都要有水 2.可以从起点引水&#xff0c;也可以互相引水。 3.费用要最小 这时我们可以想到最小生成树&#xff0c;建立一个虚拟节点即可。思路一…...

C++类模板的特化(三)

本文主要介绍类模板的特化、局部特化和缺省模板实参&#xff1b; 1.类模板的特化 类模板的特化&#xff08;Class Template Specialization&#xff09;是指为特定的模板参数提供自定义实现的过程。通过特化&#xff0c;我们可以针对某些特定的类型或条件提供不同的行为或实现…...

基于YOLOV8模型的课堂场景下人脸目标检测系统(PyTorch+Pyside6+YOLOv8模型)

摘要&#xff1a;基于YOLOV8模型的课堂场景下人脸目标检测系统可用于日常生活中检测与定位课堂场景下人脸&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的目标检测&#xff0c;另外本系统还支持图片、视频等格式的结果可视化与结果导出。本系统采用YOLOv8目标检…...

java八股文面试[数据结构]——Map有哪些子类

知识来源&#xff1a; 【23版面试突击】 用过哪些Map类&#xff0c;都有什么区别&#xff0c;HashMap是线程安全的吗&#xff1f;_哔哩哔哩_bilibili https://www.cnblogs.com/bubbleboom/p/12694013.html...

司徒理财:8.23今日黄金原油走势分析附操作策略

黄金走势分析&#xff1a;      黄金下跌遇阻&#xff0c;短线开启震荡调整走势&#xff0c;但跌势依旧没有改变&#xff0c;没有突破1906压力前&#xff0c;还是偏空走势&#xff0c;反弹继续干空。趋势行情&#xff0c;不要轻言翻转&#xff01;即便下跌结束&#xff0c;…...

使用动态IP是否会影响网络

今天我们要谈论的话题是关于动态IP和网络的关系。也许有些小伙伴对这个概念还比较陌生&#xff0c;但别担心&#xff0c;我会简单明了的给你理清楚。让我们一起看看动态IP到底能否影响到网络。 首先&#xff0c;我们先来搞明白什么是动态IP。在互联网世界中&#xff0c;每一个连…...

Linux学习笔记-常用指令说明

本文目录 一、Linux指令笔记 二、"授人以鱼,不如授人以渔" 一、Linux指令笔记 0、cd 命令是 change dir 的简写&#xff0c;它可以把终端当前所在的路径切换至目标路径。 1、mkdir 建立文件夹。是 make directory 的简写&#xff0c;它可以在文件系统中创建一个新的目…...

MyBatisPlus进阶版

1.映射 1.1自动映射 【1】表名和实体类名映射 -> 表名user 实体类名User 【2】字段名和实体类属性名映射 -> 字段名name 实体类属性名name 【3】字段名下划线命名方式和实体类属性小驼峰命名方式映射 -> 字段名 user_email 实体类属性名 userEmail MybatisPlus…...

安防视频云平台EasyNVR视频汇聚平台硬件无法进入服务器的问题处理方法

EasyNVR是基于RTSP/Onvif协议的视频接入、处理及分发的安防视频云平台&#xff0c;可提供的视频能力包括&#xff1a;设备接入、实时视频直播、录像、云存储、录像回放与检索、告警、级联等&#xff0c;平台可支持将接入的视频流进行全平台、全终端的分发&#xff0c;分发的视频…...

流媒体内容分发终极解决方案:当融合CDN与P2P视频交付结合

前言 随着互联网的发展&#xff0c;流媒体视频内容日趋增多&#xff0c;已经成为互联网信息的主要承载方式。相对传统的文字&#xff0c;图片等传统WEB应用&#xff0c;流媒体具有高数据量&#xff0c;高带宽、高访问量和高服务质量要求的特点&#xff0c;而现阶段互联网“尽力…...

根据源码,模拟实现 RabbitMQ - 内存数据管理(4)

目录 一、内存数据管理 1.1、需求分析 1.2、实现 MemoryDataCenter 类 1.2.1、ConcurrentHashMap 数据管理 1.2.2、封装交换机操作 1.2.3、封装队列操作 1.2.4、封装绑定操作 1.2.5、封装消息操作 1.2.6、封装未确认消息操作 1.2.7、封装恢复数据操作 一、内存数据管理…...

Apache Flume架构和原理

Apache Flume是一个开源的分布式、可靠的日志收集和聚合系统,旨在将大量的日志数据从不同的数据源(如应用程序、服务器、设备)收集到中心存储或数据湖中。Flume的架构设计允许用户在大规模数据流的情况下实现可靠的数据传输和处理。 Flume特性 Apache Flume是一个用于收集…...

代码随想录算法训练营day38 | LeetCode 509. 斐波那契数 70. 爬楼梯 746. 使用最小花费爬楼梯

509. 斐波那契数&#xff08;题目链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台&#xff09; 思路&#xff1a;经典的dp题。 int fib(int n){if(n 0 || n 1) return n;return fib(n-1) fib(n-2); } 70. 爬楼梯&#xff08;题目…...

河北做网站找谁/网络推广公司联系方式

jvm参数配置解析 参数说明-Xmx2048M JVM最大堆内存 -Xms2048M JVM最初始堆内存 -Xmn256MJVM年轻代大小&#xff08;整个堆大小年轻代大小 年老代大小 持久代大小 。持久代一般固定大小为64m&#xff09;-XX:MaxMetaspaceSize256MMaxMetaspaceSize是没有上限的&#xff0c;最…...

代码网站模板/口碑营销经典案例

第5.1节 Fcitx 输入法框架 注意 在 FreeBSD-14.0-Current 中可能会出现许多不可预料的奇怪的 bug&#xff08;fcitx5 诊断信息英文乱码&#xff0c;输入法显示出奇怪的汉字&#xff0c;fcitx5-qt5 环境不能正常加载……&#xff09;&#xff0c;如果条件允许应该在 FreeBSD-Rel…...

设计公司名字创意/上海优化seo

区块链技术被誉为第四次工业革命代表性成果之一&#xff0c;“最有潜力触发第五轮颠覆性革命浪潮的核心技术”&#xff0c;代表着互联网的未来&#xff0c;具有划时代意义。它被认为是与1975年的个人计算机、1993年的因特网同样具有革命性的信息技术突破。 日前&#xff0c;全…...

七牛云储存wordpress/怎么查百度竞价关键词价格

环境要求&#xff1a;必须要有jdk环境,本次讲课使用jdk1.8 结构&#xff1a;一共三个节点(zk服务器集群规模不小于3个节点),要求服务器之间系统时间保持一致。 我这里三个环境IP地址分别是&#xff1a;192.168.128.139&#xff0c;192.168.128.140&#xff0c;192.168.128.141…...

网站 关键词 挖掘/推广引流软件

命令怎么用&#xff08;三种方式&#xff09;shutdown --help shutdown --? man shutdown &#xff08;man 就是manual 手册, 指南&#xff09; 服务 service怎么知道服务的名字呢&#xff1f;用这个命令chkconfig&#xff1a; chkconfig --list 会列出所有的服务项 启动服务…...

wordpress苹果客户端/推广app平台

现在有一个df对象&#xff0c;我们想获得第i行对应的行的索引&#xff1a; 方法为&#xff1a;df.iloc[i].name。获得第i行&#xff0c;对应的行的索引。 如何获取Series对象的中的某个值&#xff0c;对应的索引&#xff1a; series1[series1.values 1].index df.iloc[] is …...