前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >魔改react-calendar还原UI设计中的打卡日历效果

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

作者头像
心安事随
发布2024-07-29 18:26:31
1010
发布2024-07-29 18:26:31
举报
文章被收录于专栏:前端大合集

需求

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

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

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

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

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

方案选择

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

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

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

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

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

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

代码语言:javascript
复制
 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

代码语言:javascript
复制
 import ClockInCalendar from './ClockInCalendar'

.......
 <ClockInCalendar></ClockInCalendar>

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

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

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

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

头部魔改

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

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

代码语言:javascript
复制
 .react-calendar__navigation{
     display: none;
 }

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

代码语言:javascript
复制
 import '../styles/customCalendar.css'

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

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

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

日历的周字去除

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

  • locale: 当前的区域设置(例如 en-USzh-CN 等),决定了日期格式的语言和地区规则。
  • date: 当前的日期对象,代表一周中的某一天。
代码语言:javascript
复制
        <Calendar
          onChange={onChange}
          value={date}
          locale="zh-CN"
          formatShortWeekday={formatShortWeekday}
        />

对应的方法编写

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

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

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

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

代码语言:javascript
复制
      <Calendar
        key={date.toString()}
        onChange={onChange}
        value={date}
        locale="zh-CN"
        tileContent={tileContent}
        formatShortWeekday={formatShortWeekday}
      />

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

大概就是做了

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

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

代码语言:javascript
复制
/**
 * 根据日期和视图类型为日历的每个瓷砖设置内容。
 *
 * 这个函数在 `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

代码语言:javascript
复制
const styles: { [key: string]: React.CSSProperties } = {
calendarContainer: {
  overflow: 'hidden',
  transition: 'max-height 0.3s ease-out',
},
calendarContainerExpanded: {
  maxHeight: '500px', 
},
calendarContainerCollapsed: {
  maxHeight: '70px', // 只显示头部和第一排日期的高度
}
};
代码语言:javascript
复制
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>

结语

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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-07-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 需求
  • 方案选择
  • 定义组件,导入库,初始化日历
  • 头部魔改
  • 日历的周字去除
  • 自定义日期单元格中的内容(状态指示+日期显示格式)
  • 日历的折叠/展开
  • 结语
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档