基于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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/92314.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

WPF基础入门-Class2-样式

WPF基础入门 Class2&#xff1a;样式 1、内联样式&#xff1a;优先度最高 <Grid><StackPanel><!--内联样式优先度高--><Button Background"Red" Height"10" Width"100"FontSize"20"Content"SB">…

Fabric.js 元素选中状态的事件与样式

本文简介 带尬猴&#xff01; 你是否在使用 Fabric.js 时希望能在选中元素后自定义元素样式或选框&#xff08;控制角和辅助线&#xff09;的样式&#xff1f; 如果是的话&#xff0c;可以放心往下读。 本文将手把脚和你一起过一遍 Fabric.js 在对象元素选中后常用的样式设置…

vue2.6及以下版本导入 TDesign UI组件库

TDesign 官方文档:https://tdesign.tencent.com/vue/components/button 我们先打开一个普通的vue项目 然后 如果你是 vue 2.6 或者 低于 2.6 在终端执行 npm i tdesign-vue如果你是 2.7 或者更高 执行 npm i tdesign-vuenaruto这里 我们 以 2.6为例 因为大部分人 用vue2 都是…

【TI毫米波雷达笔记】UART串口外设配置及驱动(以IWR6843AOP为例)

【TI毫米波雷达笔记】UART串口外设初始化配置及驱动&#xff08;以IWR6843AOP为例&#xff09; 最基本的工程建立好以后 需要给SOC进行初始化配置 int main (void) {//刷一下内存memset ((void *)L3_RAM_Buf, 0, sizeof(L3_RAM_Buf));int32_t errCode; //存放SOC初…

软件设计师学习笔记5-流水线技术

目录 1.流水线的概念 2.流水线计算 2.1流水线周期及执行时间 2.2流水线吞吐量 1.流水线的概念 考点&#xff1a;相关参数计算&#xff1a;流水线执行时间计算、流水线吞吐率、流水线加速比、流水线效率(后两者的计算中级不考) 流水线是指在程序执行时多条指令重叠进行操作…

Tomcat10安装及配置教程win11

Tomcat10安装及配置教程win11 Tomcat下载链接 Tomcat官网 Tomcat官网地址 https://tomcat.apache.org/ Tomcat的版本列表 点击上图中左侧红框内**Which version?**即可得下图 下载Tomcat 点击上图中左侧红框内红框内tomcat版本即可得下图&#xff0c;下载zip包 解压zip包…

网络安全基础知识

网络安全 1、网络安全的介绍 1.1 什么是网络安全 1.2 什么是信息系统 1.3 信息系统安全三要素 1.4 什么是网络空间安全 fireye攻击地图:https:www.fireeye.com/cyber-map/threat-map.html/. https://cybermap.kaspersky.com 1.5 安全事件分类 1.6 安全事件 勒索加密是黑客攻…

Scikit-Learn中的特征选择和特征提取详解

概要 机器学习在现代技术中扮演着越来越重要的角色。不论是在商业界还是科学领域&#xff0c;机器学习都被广泛地应用。在机器学习的过程中&#xff0c;我们需要从原始数据中提取出有用的特征&#xff0c;以便训练出好的模型。但是&#xff0c;如何选择最佳的特征是一个关键问…

解决MASM32代码汇编出错: error A2181: initializer must be a string or single item

最近用MASM32编程更新SysInfo&#xff0c;增加对IPv6连接信息的收集&#xff0c;使用到了 typedef struct _MIB_TCP6ROW_OWNER_MODULE {UCHAR ucLocalAddr[16];DWORD dwLocalScopeId;DWORD dwLocalPort;UCHAR ucRemoteAddr[16];DWORD …

【腾讯云 TDSQL-C Serverless 产品测评】“橡皮筋“一样的数据库『MySQL高压篇』

【腾讯云 TDSQL-C Serverless 产品测评】"橡皮筋"一样的数据库 活动介绍服务一览何为TDSQL &#xff1f;Serverless 似曾相识&#xff1f; 降本增效&#xff0c;不再口号&#xff1f;动手环节 --- "压力"山大实验前瞻稍作简介资源扩缩范围&#xff08;CCU&…

飞天使-k8s基础组件分析-服务与ingress

文章目录 服务的介绍服务代理服务发现连接集群外服务服务发布无头服务 服务&#xff0c;pod和dns的关系端口转发通过expose 暴露应用服务案例INGRESSMetalLB使用参考文档 服务的介绍 服务的作用是啥&#xff1f; 提供外部调用&#xff0c;保证podip的真实性看看服务解决了什么…

实时同步ES技术选型:Mysql+Canal+Adapter+ES+Kibana

基于之前的文章&#xff0c;精简操作而来 让ELK在同一个docker网络下通过名字直接访问Ubuntu服务器ELK部署与实践使用 Docker 部署 canal 服务实现MySQL和ES实时同步Docker部署ES服务&#xff0c;canal全量同步的时候内存爆炸&#xff0c;ES/Canal Adapter自动关闭&#xff0c…

Modbus转Profinet网关连接三菱变频器博图快速配置

本案例将分享如何使用兴达易控的modbus转profinet网关&#xff08;XD-MDPN100&#xff09;来连接西门子1200系列plc&#xff0c;并实现三菱变频器的485通讯兼容转modbusTCP通信。通过在博图中进行配置&#xff0c;我们可以实现设备之间的连接和通信。 首先&#xff0c;我们需要…

《QT+PCL 第五章》点云特征-PFH

QT增加点云特征PFH 代码用法代码 #include <pcl/io/pcd_io.h> #include <pcl/features/normal_3d.h> #include <pcl/features/pfh.h>int main

自动驾驶感知传感器标定安装说明

1. 概述 本标定程序为整合现开发的高速车所有标定模块,可实现相机内参标定和激光、相机、前向毫米波 至车辆后轴中心标定,标定参数串联传递并提供可视化工具验证各个模块标定精度。整体标定流程如下,标定顺序为下图前标0-->1-->2-->3,相同编号标定顺序没有强制要求…

android外卖点餐界面(期末作业)

效果展示&#xff1a; AndroidMainFest.xml <?xml version"1.0" encoding"utf-8"?> <manifest xmlns:android"http://schemas.android.com/apk/res/android"xmlns:tools"http://schemas.android.com/tools"><a…

2023年最新版IDEA安装(超详细)

个人主页&#xff1a;平行线也会相交 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 平行线也会相交 原创 收录于专栏【JavaSE_primary】 写在前面&#xff0c;IDEA的安装是建立在JDK安装好了的前提下&#xff0c;否则IDEA是无法使用的&#xff0c;具体JDK…

回归预测 | MATLAB实现GA-APSO-IBP改进遗传-粒子群算法优化双层BP神经网络多输入单输出回归预测

回归预测 | MATLAB实现GA-APSO-IBP改进遗传-粒子群算法优化双层BP神经网络多输入单输出回归预测 目录 回归预测 | MATLAB实现GA-APSO-IBP改进遗传-粒子群算法优化双层BP神经网络多输入单输出回归预测效果一览基本介绍模型描述程序设计参考资料 效果一览 基本介绍 MATLAB实现GA-…

VR/AR/眼镜投屏充电方案(LDR6020)

VR眼镜即VR头显&#xff0c;也称虚拟现实头戴式显示设备&#xff0c;随着元宇宙概念的传播&#xff0c;VR眼镜的热度一直只增不减&#xff0c;但是头戴设备的续航一直被人诟病&#xff0c;如果增大电池就会让头显变得笨重影响体验&#xff0c;所以目前最佳的解决方案还是使用VR…

Tomcat和Servlet基础知识的讲解(JavaEE初阶系列16)

目录 前言&#xff1a; 1.Tomcat 1.1Tomcat是什么 1.2下载安装 2.Servlet 2.1什么是Servlet 2.2使用Servlet来编写一个“hello world” 1.2.1创建项目&#xff08;Maven&#xff09; 1.2.2引入依赖&#xff08;Servlet&#xff09; 1.2.3创建目录&#xff08;webapp&a…