使用 React 实现自定义数据展示日历组件

目录

    • 背景
    • 实现
      • 日历组件
      • 父组件
      • 数据
    • 效果
    • 最后

背景

项目中需要实现一个日历组件,并且需要展示月,日所对应的数据(因为项目需求问题,就不统计年数据总量)。网上找了一堆,基本都不大符合项目需求,且改动麻烦(方便以后项目新需求改动),另外很少做这种需求,所以好奇心下,决定自己单独写一个组件。

实现

日历组件

import { useEffect, useState } from 'react';
import {LeftOutlined,RightOutlined,DoubleLeftOutlined,DoubleRightOutlined,CalendarOutlined,} from '@ant-design/icons';import './index.less';const weekData = ['一', '二', '三', '四', '五', '六', '日'];const CustomDatePickerModalPage = (props: any) => {const { title, dataSource, onChange } = props;// 公共获取当前日期const publicGetCurrentDateFn = () => {const date = new Date();const Y = date.getFullYear();const M = date.getMonth() + 1;const D = date.getDate();return {Y,M,D,};};// 获取年基础年份const publicGetBaseYear = (YEAR: number) => {const yearToStr = YEAR.toString();const prefixYearToStr = yearToStr.slice(0, -1);return Number(prefixYearToStr + '0');};const [datePickerState, setDatePickerState] = useState<string>('day');// 展示年const [yearArry, setYearArry] = useState<any[]>([]);const [baseYear, setBaseYear] = useState<number>(() => {const { Y } = publicGetCurrentDateFn();return publicGetBaseYear(Y);});// 展示月const [monthArry, setMonthArry] = useState<any[]>([]);const [baseMonth, setBaseMonth] = useState<number>(() => {const { M } = publicGetCurrentDateFn();return M;});// 展示当前月,上个月末尾及下个月开头日期const [monthDay, setMonthDay] = useState<any[]>([]);// 设置当前年const [currentYear, setCurrentYear] = useState<number>(() => {const { Y } = publicGetCurrentDateFn();return Y;});// 设置当前月份const [currentMonth, setCurrentMonth] = useState<number>(() => {const { M } = publicGetCurrentDateFn();return M;});// 设置当前时间const [currentDay, setCurrentDay] = useState<number>(() => {const { D } = publicGetCurrentDateFn();return D;});// 公共获取时间const publicGetDateFn = (TYPE: string = 'day',YEAR: number,MONTH: number): any => {const monthDayCount = 42;let prefixMonthDay: number[] = [];let currentMonthDay: number[] = [];let suffixMonthDay: number[] = [];prefixMonthDay.length = 0;currentMonthDay.length = 0;suffixMonthDay.length = 0;switch (TYPE) {case 'year':// 根据基准年计算10年间年度区间const initYearNum: number = publicGetBaseYear(YEAR);const prefixYearNum: number = initYearNum - 1;const currentYearNum: number[] = [];for (let i = 0; i < 10; i++) {currentYearNum.push(initYearNum + i);}const LastCurrentYearNum: number =currentYearNum[currentYearNum.length - 1] + 1;const computedAllYear: number[] = [prefixYearNum,...currentYearNum,LastCurrentYearNum,];return computedAllYear;case 'month':// 一年固定12个月const monthArry: { month: number; year: number }[] = [];for (let i = 0; i < 12; i++) {monthArry.push({ month: i + 1, year: YEAR });}return monthArry;case 'day':const step: Date = new Date(YEAR, MONTH, 0);const monthDayLen: number = step.getDate();const monthOneToWeek: number = new Date(`${YEAR}-${MONTH}-1`).getDay();if (monthOneToWeek === 1) {// 星期一// 当前月份天数for (let i = 0; i < monthDayLen; i++) {currentMonthDay.push(i + 1);}// 下个月天数for (let i = 0; i < monthDayCount - monthDayLen; i++) {suffixMonthDay.push(i + 1);}} else {// 星期二到星期日// 获取上个月的总天数const step = new Date(YEAR, MONTH - 1, 0);const prefixMonthDayLen = step.getDate();// 上个月展示天数const prefixNum = monthOneToWeek === 0 ? 6 : monthOneToWeek - 1;const prefixDayNum = prefixMonthDayLen - prefixNum;for (let i = prefixDayNum; i < prefixMonthDayLen; i++) {prefixMonthDay.push(i + 1);}// 当前月份展示天数for (let i = 0; i < monthDayLen; i++) {currentMonthDay.push(i + 1);}// 下个月展示天数for (let i = 0; i < monthDayCount - monthDayLen - prefixNum; i++) {suffixMonthDay.push(i + 1);}}const formatPrefixMonthDay: {type: string;day: number;month: number;year: number;}[] = [];const formatCurrentMonthDay: {type: string;day: number;month: number;year: number;}[] = [];const formatSuffixMonthDay: {type: string;day: number;month: number;year: number;}[] = [];prefixMonthDay?.length > 0 &&prefixMonthDay.forEach((item: number) =>formatPrefixMonthDay.push({type: 'up',day: item,month: MONTH,year: YEAR,}),);currentMonthDay?.length > 0 &&currentMonthDay.forEach((item: number) =>formatCurrentMonthDay.push({type: 'current',day: item,month: MONTH,year: YEAR,}),);suffixMonthDay?.length > 0 &&suffixMonthDay.forEach((item: number) =>formatSuffixMonthDay.push({type: 'lower',day: item,month: MONTH,year: YEAR,}),);const computedAllMonthDay: {type: string;day: number;month: number;year: number;}[] = [...formatPrefixMonthDay,...formatCurrentMonthDay,...formatSuffixMonthDay,];return computedAllMonthDay;}};// 展示年份const handleYearFn = (type: string,value: number = publicGetCurrentDateFn()['Y'],) => {if (type === '1') {setDatePickerState('year');if (currentYear === baseYear) {const data = publicGetDateFn('year', baseYear, currentMonth);setYearArry(data);} else {const data = publicGetDateFn('year', baseYear, currentMonth);setYearArry(data);}}if (type === '2') {setDatePickerState('month');setCurrentYear(value);const data = publicGetDateFn('month', value, currentMonth);setMonthArry(data);onChange('month', `${value}`);}};// 展示月份, 1:点击头,2:点击每一月const handleMonthFn = (type: string, value: number = 0) => {if (type === '1') {setDatePickerState('month');const data = publicGetDateFn('month', currentYear, value);setMonthArry(data);onChange('month', `${currentYear}`);}if (type === '2') {setDatePickerState('day');setCurrentMonth(value);const data = publicGetDateFn('day', currentYear, value);setMonthDay(data);onChange('day', `${currentYear}-${value}`);}};// 展示每天const handleDateFn = (value: number) => {setDatePickerState('day');// const data = publicGetDateFn('day', ,value);};// 左右 icon 图标年份切换const publicGetYearToDateFn = (TYPE: string) => {if (TYPE === 'UP') {if (datePickerState === 'year') {const computedBaseYear = publicGetBaseYear(baseYear - 1);setBaseYear(computedBaseYear);const data = publicGetDateFn('year', computedBaseYear, currentMonth);setYearArry(data);} else {const computedCurrentYear = currentYear - 1;setCurrentYear(computedCurrentYear);if (datePickerState === 'day') {const data = publicGetDateFn('day',computedCurrentYear,currentMonth,);setMonthDay(data);onChange('day', `${computedCurrentYear}-${currentMonth}`);} else {onChange('month', `${computedCurrentYear}`);}}}if (TYPE === 'LOWER') {if (datePickerState === 'year') {const computedBaseYear = publicGetBaseYear(baseYear + 10);setBaseYear(computedBaseYear);const data = publicGetDateFn('year', computedBaseYear, currentMonth);setYearArry(data);} else {const computedCurrentYear = currentYear + 1;setCurrentYear(computedCurrentYear);if (datePickerState === 'day') {const data = publicGetDateFn('day',computedCurrentYear,currentMonth,);setMonthDay(data);onChange('day', `${computedCurrentYear}-${currentMonth}`);} else {onChange('month', `${computedCurrentYear}`);}}}};// 左右 icon 图标月份切换const publicGetMonthToDateFn = (TYPE: string) => {let computedCurrentMonth = currentMonth;if (TYPE === 'UP') {if (currentMonth - 1 > 0) {computedCurrentMonth = currentMonth - 1;}}if (TYPE === 'LOWER') {if (currentMonth + 1 <= 12) {computedCurrentMonth = currentMonth + 1;}}setCurrentMonth(computedCurrentMonth);const data = publicGetDateFn('day', currentYear, computedCurrentMonth);setMonthDay(data);onChange('day', `${currentYear}-${computedCurrentMonth}`);};useEffect(() => {const { Y, M, D } = publicGetCurrentDateFn();setBaseYear(publicGetBaseYear(Y));setBaseMonth(M);setCurrentYear(Y);setCurrentMonth(M);setCurrentDay(D);const data = publicGetDateFn('day', Y, M);console.log('初始化时间:', data);setMonthDay(data);}, []);// 设置系统当前天高亮const getCurrentDayMaskFn = ({ type, day, month, year }: any) => {const { Y, M, D } = publicGetCurrentDateFn();if (type === 'current' && day === D && month === M && year === Y)return 'tbody-td-active';else return '';};// 设置系统当前月高亮const getCurrentMonthMaskFn = ({month,year,}: {month: number;year: number;}) => {const { Y, M } = publicGetCurrentDateFn();if (year === Y && month === M) return 'tbody-td-active';else return '';};// 设置系统当前年高亮const getCurrentYearMaskFn = (year: number) => {const { Y, M } = publicGetCurrentDateFn();if (year === Y) return 'tbody-td-active';else return '';};// 获取当前时间,主要用来获取对应日期数据const getCurrentDateFn = (value: number): number => {switch (datePickerState) {// case 'day'://     return Number(`${currentYear}${currentMonth < 10 ? `0${currentMonth}` : currentMonth}${value < 10 ? `0${value}` : value}`);case 'month':return Number(`${currentYear}${value < 10 ? `0${value}` : value}`);case 'year':return Number(`${value}`);default:return Number(`${currentYear}${currentMonth < 10 ? `0${currentMonth}` : currentMonth}${value < 10 ? `0${value}` : value}`,);}};return (<>{/* <CalendarOutlined /> */}<div className="customDatePickerWrp"><div className="header-Wrp"><div className="header-title">{title}</div><ul className="header-operate-wrp"><li key={0} onClick={() => publicGetYearToDateFn('UP')}><DoubleLeftOutlined /></li>{datePickerState === 'day' && (<li key={1} onClick={() => publicGetMonthToDateFn('UP')}><LeftOutlined /></li>)}<li key={2} className="yearMonthWrp">{datePickerState === 'year' && (<div onClick={() => handleYearFn('1')}>{baseYear} - {baseYear + 9}</div>)}{datePickerState !== 'year' && (<div onClick={() => handleYearFn('1')}>{currentYear}</div>)}{datePickerState === 'day' && (<div onClick={() => handleMonthFn('1')}>{currentMonth}</div>)}</li>{datePickerState === 'day' && (<li key={3} onClick={() => publicGetMonthToDateFn('LOWER')}><RightOutlined /></li>)}<li key={4} onClick={() => publicGetYearToDateFn('LOWER')}><DoubleRightOutlined /></li></ul></div><div className="content-Wrp">{// 展示日期datePickerState === 'day' && (<><ul className="table-thead-wrp">{weekData.map((item: string, index: number) => (<li className="table-td" key={index}>{item}</li>))}</ul><ul className="table-tbody-wrp">{monthDay.map((item, index: number) => {return (<likey={index}className={`tbody-td ${item['type'] !== 'current'? 'tbody-otherMonthDay-td': ''} ${getCurrentDayMaskFn(item)}`}><div>{item['day']}</div><div>{dataSource[getCurrentDateFn(item['day'])]}</div></li>);})}</ul></>)}{// 展示月份datePickerState === 'month' && (<ul className="table-tbody-month-wrp">{monthArry?.length > 0 &&monthArry.map((item, index: number) => {return (<likey={index}className={`tbody-month-td ${getCurrentMonthMaskFn(item,)}`}onClick={() => handleMonthFn('2', item['month'])}><div>{item['month']}</div><div>{dataSource[getCurrentDateFn(item['month'])]}</div></li>);})}</ul>)}{// 展示年份datePickerState === 'year' && (<ul className="table-tbody-year-wrp">{yearArry?.length > 0 &&yearArry.map((item, index: number) => {return (<likey={index}className={`tbody-year-td ${getCurrentYearMaskFn(item,)}`}onClick={() => handleYearFn('2', item)}><div>{item}</div><div>{dataSource[getCurrentDateFn(item)]}</div></li>);})}</ul>)}</div></div></>);
};export default CustomDatePickerModalPage;

父组件

const parentModalPage = () => {// 请查看月/日数据const customDatePickerData = {"202301": 286687680,"202302": 55312480,"202303": 61211920,"202304": 59266360,"202305": 61211920,"202306": 59245440,"202307": 61211920,"202308": 206082920,"202309": 812388661.2,"202310": 778804150,"202311": 487160,"202312": 43771360};return (<div style={{ width: '100%', height: '100%', padding: '0 20px 20px 20px' }}><CustomDatePicker title="历史用能日历" dataSource={customDatePickerData} onChange={(type: string, value: string) => {console.log('历史用能日历::', type, value, typeof value, customDatePickerData);// 调用接口获取数据getEnergyUsageStatsFn(true, {granularity: type,startDate: publicGetCurrentDateFn(type, value.toString())['startDate'],endDate: publicGetCurrentDateFn(type, value.toString())['endDate'],});}} /></div>)
};

数据

  • 月数据

    // 返回数据格式-月份数据
    const customDatePickerData = {"202301": 286687680,"202302": 55312480,"202303": 61211920,"202304": 59266360,"202305": 61211920,"202306": 59245440,"202307": 61211920,"202308": 206082920,"202309": 812388661.2,"202310": 778804150,"202311": 487160,"202312": 43771360
    };
    
  • 日数据

    const customDatePickerData = {"20231001": 5920360,"20231002": 5920360,"20231003": 5920360,"20231004": 5941280,"20231005": 5920360,"20231006": 5920360,"20231007": 5920360,"20231008": 5941280,"20231009": 0,"20231010": 203030378.2,"20231011": 5920360,"20231012": 32453714,"20231013": 35985720,"20231014": 29342320,"20231015": 49822720,"20231016": 23248120,"20231017": 37049520,"20231018": 477835490.2,"20231019": 740848323.8,"20231020": 168360,"20231021": 159280,"20231022": 169960,"20231023": 14413760,"20231024": 14705280,"20231025": 287880,"20231026": 30342680,"20231027": 8178880,"20231028": 422400,"20231029": 28487040,"20231030": 9168480,"20231031": 29014320
    }
    

效果

  • 月度数据
    在这里插入图片描述

  • 年度数据
    在这里插入图片描述

  • 年统计:
    注意:目前年度总数据暂未统计展示,不过可以根据自己的需求进行修改。
    在这里插入图片描述

最后

将上面的组件引入应该是开箱即用,如果有问题请评论区多多留言。

如果对大家有所帮助,请咚咚大家的【发财黄金手指:点赞收藏

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OpenHarmony鸿蒙原生应用开发,ArkTS、ArkUI学习踩坑学习笔记,持续更新中。

一、AMD处理器win10系统下&#xff0c;DevEco Studio模拟器启动失败解决办法。 结论&#xff1a;在BIOS里面将Hyper-V打开&#xff0c;DevEco Studio模拟器可以成功启动。 二、ArkTS自定义组件导出、引用实现。 如果在另外的文件中引用组件&#xff0c;需要使用export关键字导…

3ds max软件中的一些常用功能分享!

3ds max软件有很多小伙伴反馈说&#xff0c;明明有很多3ds max教程资料。却不知道如何入门3dmax。 掌握3dmax基本功能是开始使用3dmax的基础之一&#xff0c;所以&#xff0c;小编带大家盘点一下3dmax常用操作。 3dmax常用功能介绍如下&#xff0c;快快跟着小编一起看起来。 1…

预测性维护在汽车制造行业中的应用

汽车制造行业是一个高度复杂和精细化的领域&#xff0c;依赖于各种设备来完成生产流程。这些设备包括机械装配线、焊接机器人、喷涂设备、传送带等。然而&#xff0c;这些设备在长时间运行中不可避免地会遇到各种故障&#xff0c;给生产进程带来延误和成本增加。为了应对这一挑…

LeetCode Hot100 79.单词搜索

题目&#xff1a; 给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 单词必须按照字母顺序&#xff0c;通过相邻的单元格内的字母构成&#xff0c;其中“相邻”单元格是那…

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Button按钮组件

鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#xff08;ArkUI&#xff09;之Button按钮组件 一、操作环境 操作系统: Windows 10 专业版 IDE:DevEco Studio 3.1 SDK:HarmonyOS 3.1 二、Button按钮组件 Button 组件也是基础组件之一&#xff0c;和其它基础组件不…

Linux之grep、sed、awk

目录 1.grep 2.sed 3.awk 1.grep grep 擅长过滤查找&#xff0c;按行进行过滤 例&#xff1a; 当有用户对我们的主机进行爆破攻击时&#xff0c;我们可以使用grep将 ip 查找出来&#xff0c;进行封锁等处理 在 /var/log 目录下的 secure 文件中存放在用户登录连接信息&am…

自动化测试成本高效果差,意义在哪?

自动化测试的成本高效果差&#xff1f;首先这个结论就太过武断了一些。 任何技术都需要放到适合的地方去使用&#xff0c;否则一定是达不到理想的效果的。举例大炮打蚊子&#xff0c;同样是成本高效果差&#xff0c;难道大炮就没有存在的意义了吗&#xff1f; 当然不是&#…

ATKXCOM串口助手接受中文字符乱码问题

中文乱码大多是编码格式问题&#xff0c;如心知天气API返回的数据编码格式为UTF-8格式&#xff0c;同理串口调试助手需要更改为对应的编码格式&#xff0c;正点原子的串口调试助手具有多种编码格式可以更改。 PS:点击左下角设置图标即可设置

OpenAI发布AGI安全风险框架!董事会可随时叫停GPT-5等模型发布,奥特曼也得乖乖听话

OpenAI 再次强调模型安全性&#xff01;AGI 安全团队 Preparedness 发布模型安全评估与监控框架&#xff01; 这两天关注 AI 圈新闻的小伙伴们可能也有发现&#xff0c;近期的 OpenAI 可谓进行了一系列动作反复强调模型的“安全性”。 前有 OpenAI 安全系统&#xff08;Safety…

工业镜头常见的类型

在机器视觉中&#xff0c;工业镜头作为机器视觉系统的核心部件&#xff0c;常常需要和工业相机搭配使用。工业镜头&#xff0c;属于一种光学系统。光学系统是指由透镜、反射镜、棱镜和光阑等多种光学元件按一定次序组合成的系统。那么工业镜头都有哪些类型&#xff1f; 一、按照…

搭建APP应用程序如何选择服务器

Hello&#xff0c;各位同学们好&#xff01;我是咕噜铁蛋&#xff0c;我经常收到许多关于如何搭建APP的询问。其中&#xff0c;如何选择服务器是许多初创企业和开发者经常面临的问题。带着这些问题我也通过一些科技手段收集整理了些知识&#xff0c;今天我就和大家来来探讨如何…

BKP 备份寄存器 RTC 实时时钟-stm32入门

这一章节我们要讲的主要内容是 RTC 实时时钟&#xff0c;对应手册&#xff0c;是第 16 章的位置。 实时时钟这个东西&#xff0c;本质上是一个定时器&#xff0c;但是这个定时器&#xff0c;是专门用来产生年月日时分秒&#xff0c;这种日期和时间信息的。所以学会了 STM32 的…

HTML + JavaScript 实现网页录制音频与下载

HTML JavaScript 实现网页录制音频与下载 HTML JavaScript 实现网页录制音频与下载简介getUserMediaMediaRecorder获取和处理音频流实现音频的录制和播放音频效果的处理实时语音通话的应用兼容性和 Latency 问题 项目代码运行实例参考源码下载 HTML JavaScript 实现网页录制…

银行测试:第三方支付平台业务流,功能/性能/安全测试方法

1、第三方支付平台的功能和结构特点 在信用方面&#xff0c;第三方支付平台作为中介&#xff0c;在网上交易的商家和消费者之间作一个信用的中转&#xff0c;通过改造支付流程来约束双方的行为&#xff0c;从而在一定程度上缓解彼此对双方信用的猜疑&#xff0c;增加对网上购物…

【lesson18】MySQL内置函数(1)日期函数和字符串函数

文章目录 日期函数函数使用具体使用案例建表插入数据建表插入数据 字符串函数函数使用具体使用案例建表插入数据测试 日期函数 函数使用 获得年月日&#xff1a; 获得时分秒&#xff1a; 获得时间戳&#xff1a; 获得现在的时间&#xff1a; 在日期的基础上加日期&#xf…

C++ Qt开发:TableWidget表格组件

Qt 是一个跨平台C图形界面开发库&#xff0c;利用Qt可以快速开发跨平台窗体应用程序&#xff0c;在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置&#xff0c;实现图形化开发极大的方便了开发效率&#xff0c;本章将重点介绍TableWidget表格组件的常用方法及灵活运用。 …

基于python的leetcode算法介绍之递归

文章目录 零 算法介绍一 简单示例 辗转相除法Leetcode例题与思路[509. 斐波那契数](https://leetcode.cn/problems/fibonacci-number/)解题思路&#xff1a;题解&#xff1a; [206. 反转链表](https://leetcode.cn/problems/reverse-linked-list/)解题思路&#xff1a;题解&…

Jmeter中使用py插件

-安装插件 1、下载插件jython-standalone-2.7.0.jar到jmeter的lib\ext目录下 链接&#xff1a; https://pan.baidu.com/s/13ZXtUwoQEV62M98GaIR26w 提取码&#xff1a;ioyk 2、重启jmeter&#xff0c;查看是否生效&#xff0c;如果这个语言有python的选项说明可以了&#xf…

VMware虚拟机安装Linux操作系统

1.CentOS 7安装 软件选择&#xff0c;安装桌面系统 2.配置虚拟机网卡 3.连接Xshell

测试用例评审流程优化

测试用例评审是QA日常工作流程中的关键一环&#xff0c;是QA同学完善测试用例、交流测试经验的好机会。 负责组内测试用例建设以来&#xff0c;作者对于评审流程做了一些优化工作。本文作者将整个优化过程中的心得体会做了一个总结&#xff0c;希望能给大家带来帮助。 01 原始流…