我们需要还原UI给我们的设计图里面的日历样式, 找到了一款第三方日历库,我们如何进行魔改呢?
这是react-calendar
库官方示例中的代码,我们导入使用默认样式就是这个样子
我们需要做成下面的这个样子
咋一看,确实感觉没有什么思路, 不过跟着步伐来,你会发现其实不复杂.
因为接到这样的一个需求, 我大概了看了一下UI设计图,然后第一反应就是去掘金,GITHUB去找有没有对应的轮子库, 但找了一圈,没有找到像这种个性化定义的. 但是要是自己去写吧,自己不一定能写的出来, 而且耗时耗力. 所以也没多想就直接找了一个react用的较多的日历库react-calendar
.
下面是关于这个库的一些介绍:
React Calendar 是一个用于 React 的灵活且易于使用的日历组件。它允许开发人员在他们的 React 应用程序中轻松集成日期选择功能。以下是对 React Calendar 的详细介绍:
二话不说,我们直接开始编写.
我们定义一个组件 ClockInCalendar.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
import ClockInCalendar from './ClockInCalendar'
.......
<ClockInCalendar></ClockInCalendar>
此时我们的页面就是这样的
我们需要修改哪些东西呢,观察一开始的那个成品就会发现:
改写成我们的头部样式
]一, 二, 三
数字即可
打卡状态
, [绿色:已打卡
] , [黄色:请假
], [红色:未打卡
]高亮显示
展开\折叠的效果
还有好多小细节需要处理, 不要担心, 跟着我的步伐一步步来, 不难实现!
我们打开F12 就会看到这个, 我们的思路是 将这个进行隐藏display:none
, 然后编写自己的DOM结构 + CSS样式
.
首先创建一个自定义的css文件, 专门用来覆盖
组件的内部样式的
.react-calendar__navigation{
display: none;
}
然后在_app.tsx [NEXT项目]里面进行一个全局导入
import '../styles/customCalendar.css'
此时我们打开页面, 就会发现日历的头部没有了
然后我们就可以编写头部的结构和样式了,
这里就不放代码, 大概就是左边一部分, 右边一部分, 其中左边又可以分为日历icon + 年月份 + 打卡数量, 右边则是上个月和下个月的button.
formatShortWeekday
是 react-calendar
库中的一个方法,用于格式化一周中每一天的显示名称。这个方法主要用于显示日历组件中的星期几的缩写形式。
locale
: 当前的区域设置(例如 en-US
、zh-CN
等),决定了日期格式的语言和地区规则。date
: 当前的日期对象,代表一周中的某一天。 <Calendar
onChange={onChange}
value={date}
locale="zh-CN"
formatShortWeekday={formatShortWeekday}
/>
对应的方法编写
const formatShortWeekday = (locale: any, date: Date) => {
const weekdays = ['日', '一', '二', '三', '四', '五', '六'];
return weekdays[date.getDay()];
};
date.getDay()
是Date
对象的一个方法,用于获取一周中某一天的索引。这个方法返回的值是一个整数,代表一周中的某一天。具体来说,返回值是一个从0
到6
的整数,分别对应一周的七天。
tileContent
是一个非常有用的属性,允许你自定义日历每个日期单元格中的内容。这个属性接收一个函数作为参数,你可以通过这个函数提供自定义的渲染逻辑来展示日期信息、事件、标记等内容。
<Calendar
key={date.toString()}
onChange={onChange}
value={date}
locale="zh-CN"
tileContent={tileContent}
formatShortWeekday={formatShortWeekday}
/>
这个就是上面函数的编写, 可以看下注释.
大概就是做了
绿色
红色
黄色
背景颜色的高亮
最后将这些上面格式化之后的数据进行一个数据填入, 最后将这个dom结构进行return 返回出去
/**
* 根据日期和视图类型为日历的每个瓷砖设置内容。
*
* 这个函数在 `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
const styles: { [key: string]: React.CSSProperties } = {
calendarContainer: {
overflow: 'hidden',
transition: 'max-height 0.3s ease-out',
},
calendarContainerExpanded: {
maxHeight: '500px',
},
calendarContainerCollapsed: {
maxHeight: '70px', // 只显示头部和第一排日期的高度
}
};
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>
以上就是我的方法,如果能对您有些帮助,希望可以点个赞,有任何问题,也欢迎进行交流!!!