魔改react-calendar还原UI设计中的打卡日历效果

简介: 魔改react-calendar还原UI设计中的打卡日历效果


需求

我们需要还原UI给我们的设计图里面的日历样式, 找到了一款第三方日历库,我们如何进行魔改呢?

这是react-calendar 库官方示例中的代码,我们导入使用默认样式就是这个样子

image.png

我们需要做成下面的这个样子

image.png

咋一看,确实感觉没有什么思路, 不过跟着步伐来,你会发现其实不复杂.

因为接到这样的一个需求, 我大概了看了一下UI设计图,然后第一反应就是去掘金,GITHUB去找有没有对应的轮子库, 但找了一圈,没有找到像这种个性化定义的. 但是要是自己去写吧,自己不一定能写的出来, 而且耗时耗力. 所以也没多想就直接找了一个react用的较多的日历库react-calendar.

方案选择

下面是关于这个库的一些介绍:

React Calendar 是一个用于 React 的灵活且易于使用的日历组件。它允许开发人员在他们的 React 应用程序中轻松集成日期选择功能。以下是对 React Calendar 的详细介绍:

  1. 简单易用
  • React Calendar 提供了简单直观的 API,方便开发人员快速上手并集成到项目中。
  1. 高度可定制
  • 组件提供了多种配置选项,允许开发人员根据需要自定义日历的外观和行为。例如,可以设置日期格式、最小和最大日期、禁用特定日期等。
  1. 支持多种视图
  • React Calendar 支持多种视图模式,包括月视图、年视图等,用户可以根据需求切换视图。
  1. 事件处理
  • 组件提供了丰富的事件处理函数,如日期选择、视图切换等,方便开发人员在不同的交互事件中执行自定义逻辑。
  1. 国际化支持
  • React Calendar 支持多种语言和区域设置,可以轻松实现多语言的日期显示和选择功能。

二话不说,我们直接开始编写.

定义组件,导入库,初始化日历

我们定义一个组件 ClockInCalendar.tsx . 然后将官网的示例直接填写进去.

tsx

import { useState } from 'react';
 import Calendar from 'react-calendar';
 
 type ValuePiece = Date | null;
 
 type Value = ValuePiece | [ValuePiece, ValuePiece];
 
 function ClockInCalendar() {
   const [value, onChange] = useState<Value>(new Date());
 
   return (
     <div>
       <Calendar onChange={onChange} value={value} />
     </div>
   );
 }
 
 export default ClockInCalendar

然后在其他组件进行导入即可

app.tsx

tsx

import ClockInCalendar from './ClockInCalendar'
.......
 <ClockInCalendar></ClockInCalendar>

此时我们的页面就是这样的

image.png

我们需要修改哪些东西呢,观察一开始的那个成品就会发现:

  • 顶部全部进行修改 [改写成我们的头部样式]
  • 周一, 周二, 周三, 转换为一, 二, 三
  • 日期的话只需要数字即可
  • 数字下方需要显示打卡状态 , [绿色:已打卡] , [黄色:请假], [红色:未打卡]
  • 当天日期的背景颜色需要高亮显示
  • 日历可以进行一个展开\折叠的效果
  • ....

还有好多小细节需要处理, 不要担心, 跟着我的步伐一步步来, 不难实现!

头部魔改

image.png

我们打开F12 就会看到这个, 我们的思路是 将这个进行隐藏display:none, 然后编写自己的DOM结构 + CSS样式.

首先创建一个自定义的css文件, 专门用来覆盖组件的内部样式的

css

.react-calendar__navigation{
     display: none;
 }

然后在_app.tsx [NEXT项目]里面进行一个全局导入

tsx

import '../styles/customCalendar.css'

此时我们打开页面, 就会发现日历的头部没有了

image.png

然后我们就可以编写头部的结构和样式了,

这里就不放代码, 大概就是左边一部分, 右边一部分, 其中左边又可以分为日历icon + 年月份 + 打卡数量, 右边则是上个月和下个月的button.

日历的周字去除

formatShortWeekdayreact-calendar 库中的一个方法,用于格式化一周中每一天的显示名称。这个方法主要用于显示日历组件中的星期几的缩写形式。

  • locale: 当前的区域设置(例如 en-USzh-CN 等),决定了日期格式的语言和地区规则。
  • date: 当前的日期对象,代表一周中的某一天。

tsx

<Calendar
          onChange={onChange}
          value={date}
          locale="zh-CN"
          formatShortWeekday={formatShortWeekday}
        />

对应的方法编写

tsx

const formatShortWeekday = (locale: any, date: Date) => {
    const weekdays = ['日', '一', '二', '三', '四', '五', '六'];
    return weekdays[date.getDay()];
  };

date.getDay()Date 对象的一个方法,用于获取一周中某一天的索引。这个方法返回的值是一个整数,代表一周中的某一天。具体来说,返回值是一个从 06 的整数,分别对应一周的七天。

自定义日期单元格中的内容(状态指示+日期显示格式)

tileContent 是一个非常有用的属性,允许你自定义日历每个日期单元格中的内容。这个属性接收一个函数作为参数,你可以通过这个函数提供自定义的渲染逻辑来展示日期信息、事件、标记等内容。

tsx

<Calendar
        key={date.toString()}
        onChange={onChange}
        value={date}
        locale="zh-CN"
        tileContent={tileContent}
        formatShortWeekday={formatShortWeekday}
      />

这个就是上面函数的编写, 可以看下注释.

大概就是做了

  • 格式化日期
  • 比对MocK的数据日期的状态,
  • 如果是completed, 就设置指示状态的背景颜色为 绿色
  • 如果是missed, 就设置指示状态的背景颜色为 红色
  • 如果是leave, 就设置指示状态的背景颜色为 黄色
  • 比对当天的日期, 对当天的日期进行一个背景颜色的高亮

最后将这些上面格式化之后的数据进行一个数据填入, 最后将这个dom结构进行return 返回出去

tsx

/**
 * 根据日期和视图类型为日历的每个瓷砖设置内容。
 *
 * 这个函数在 `month` 视图中为每个日期的瓷砖返回自定义内容,包括日期数字和状态指示点。
 *
 * @function
 * @param {{ date: Date, view: 'month' | 'year' | 'decade' | 'century' }} tileInfo - 包含日期和视图类型的信息对象。
 * @returns {JSX.Element | null} 返回一个包含日期数字和状态指示点的 JSX 元素,或者在其他视图类型中返回 `null`。
 * @example
 * // 在组件中使用示例
 * const content = tileContent({ date, view });
 * return <div>{content}</div>;
 */
  const tileContent = ({ date, view }: { date: Date, view: string }): JSX.Element | null => {
    if (view === 'month') {
      const formattedDate = format(date, 'd', { locale: zhCN });
      
      const dateString = format(date, 'yyyy-MM-dd');
      let dotStyle = styles.transparentDot;
  
      // 进行日期状态的判断,然后分别给状态指示添加不同的css的背景颜色.
      if (data[dateString] === 'completed') {
        dotStyle = { ...styles.dot, backgroundColor: '#00ee00' };
      } else if (data[dateString] === 'missed') {
        dotStyle = { ...styles.dot, backgroundColor: '#FF4500' };
      } else if (data[dateString] === 'leave') {
        dotStyle = { ...styles.dot, backgroundColor: '  #FFD700' };
      }
        
    // 当前日期的背景颜色进行一个高亮显示
      // 判断是否为当天
      // 获取当天
      const currentDate = new Date();
      const tileStyle = isSameDay(date, currentDate)
        ? { ...styles.customCalendarTile, ...styles.highlightedTile }
        : styles.customCalendarTile;
      return (
        // 日期数字
        <div className='flex flex-col items-center'>
          <div style={tileStyle}
            className='hover:bg-slate-100'
          >
            {formattedDate}
          </div>
          {/* 状态标识 */}
          <div style={dotStyle}></div>
        </div>
      );
    }
    return null;
  };

日历的折叠/展开

这里先说下思路

通过在日历组件外面套一侧DIV, 分别为它创建两个类名

  • 一个设置高为80px [正好显示一行的高度]
  • 一个设置高为500px [全部显示]

通过点击动态添加类名,即可Ok

tsx

const styles: { [key: string]: React.CSSProperties } = {
calendarContainer: {
  overflow: 'hidden',
  transition: 'max-height 0.3s ease-out',
},
calendarContainerExpanded: {
  maxHeight: '500px', 
},
calendarContainerCollapsed: {
  maxHeight: '70px', // 只显示头部和第一排日期的高度
}
};

tsx

const [collapsed, setCollapsed] = useState<boolean>(false);  
const toggleCollapse = () => {
    setCollapsed(!collapsed);
  };
 <div style={{
        ...styles.calendarContainer,
        ...(collapsed ? styles.calendarContainerCollapsed : styles.calendarContainerExpanded)
      }}>
        <Calendar
          key={date.toString()}
          onChange={onChange}
          value={date}
          className={`w-full h-auto ${ClockInCalendarStyle.customCalendar}`} // 添加自定义样式类
          locale="zh-CN"
          tileContent={tileContent}
          formatShortWeekday={formatShortWeekday}
        />
</div>
<button
        onClick={toggleCollapse}
        style={collapsed ? { ...styles.collapseButton, ...styles.collapseButtonHover } : styles.collapseButton}
      >
        {collapsed ? '⬆️ 展开' : '⬇️ 收起'}
</button>

结语

以上就是我的方法,如果能对您有些帮助,希望可以点个赞,有任何问题,也欢迎进行交流!!!


目录
相关文章
|
6月前
|
设计模式 前端开发 数据可视化
【第4期】一文了解React UI 组件库
【第4期】一文了解React UI 组件库
360 0
|
1月前
|
前端开发 数据可视化 JavaScript
🚀打造卓越 UI:2024 年不容错过的 9 个 React UI 组件库✨
本文介绍了2024年最受欢迎的9个React UI组件库,每一个都在设计、功能和定制化上有独特的优势,包括Material UI、Ant Design、Chakra UI等。这些组件库为开发者提供了强大、灵活的工具,可以帮助构建现代化、无障碍且高效的Web应用程序。文章详细分析了每个库的特点、适用场景以及关键功能,帮助开发者在项目中做出最合适的选择,无论是打造企业级仪表板还是时尚的用户界面。
70 6
🚀打造卓越 UI:2024 年不容错过的 9 个 React UI 组件库✨
|
2月前
|
前端开发 JavaScript
React技术栈-React UI之ant-design使用入门
关于React技术栈中使用ant-design库的入门教程,包括了创建React应用、搭建开发环境、配置按需加载、编写和运行代码的步骤,以及遇到错误的解决方法。
38 2
React技术栈-React UI之ant-design使用入门
|
2月前
|
传感器 监控 前端开发
WHAT - 通过 react-use 源码学习 React(UI 篇)
WHAT - 通过 react-use 源码学习 React(UI 篇)
|
6月前
|
前端开发 JavaScript
详解React:Props构建可复用UI的基石
详解React:Props构建可复用UI的基石
39 0
|
资源调度 前端开发 JavaScript
关于react-admin+material ui项目的总结
关于react-admin+material ui项目的总结
163 0
|
前端开发
前端项目实战壹佰叁拾react-admin+material ui-react-admin之SelectColumnsButton之使用
前端项目实战壹佰叁拾react-admin+material ui-react-admin之SelectColumnsButton之使用
55 0
|
前端开发 JavaScript
组件与Props:React中构建可复用UI的基石
组件与Props:React中构建可复用UI的基石
81 0
|
8天前
|
搜索推荐 Android开发 开发者
探索安卓开发中的自定义视图:打造个性化UI组件
【10月更文挑战第39天】在安卓开发的世界中,自定义视图是实现独特界面设计的关键。本文将引导你理解自定义视图的概念、创建流程,以及如何通过它们增强应用的用户体验。我们将从基础出发,逐步深入,最终让你能够自信地设计和实现专属的UI组件。
|
1月前
|
开发框架 JavaScript 前端开发
鸿蒙NEXT开发声明式UI是咋回事?
【10月更文挑战第15天】鸿蒙NEXT的声明式UI基于ArkTS,提供高效简洁的开发体验。ArkTS扩展了TypeScript,支持声明式UI描述、自定义组件及状态管理。ArkUI框架则提供了丰富的组件、布局计算和动画能力。开发者仅需关注数据变化,UI将自动更新,简化了开发流程。此外,其前后端分层设计与编译时优化确保了高性能运行,利于生态发展。通过组件创建、状态管理和渲染控制等方式,开发者能快速构建高质量的鸿蒙应用。
114 3
下一篇
无影云桌面