可折叠,可标记日历
样式:
实现代码
index.tsx
import { Image } from '@tarojs/components';
import View from '@/components/GymComponents/GymView';
import { useState } from 'react';
import classnames from 'classnames';
import dayjs from 'dayjs';
import styles from './index.module.scss';
const weekdaysList = ['日', '一', '二', '三', '四', '五', '六'];
// 获取当月天数据
const getWeekListByMonth = (monthObj: dayjs.Dayjs, selectedDay: string) => {
const firstMonthDay = monthObj.startOf('month');
const lastMonthDay = monthObj.endOf('month');
const firstShowDay = firstMonthDay.startOf('week');
const lastShowDay = lastMonthDay.endOf('week');
const weekList = [];
let selectedDayListIndex = 0;
let weekListIndex = 0;
for (let day = firstShowDay; day.isBefore(lastShowDay); day = day.add(7, 'day')) {
const dayList = [];
for (let index = 0; index < 7; index++) {
const currentDay = day.add(index, 'day');
dayList.push(currentDay);
// 获取选中行
if (currentDay.format('YYYY-MM-DD') == selectedDay) {
selectedDayListIndex = weekListIndex;
}
}
weekListIndex++;
weekList.push(dayList);
}
return { weekList, selectedDayListIndex };
};
// 单元格处理
const MonthCell = props => {
const { day, currentMonth, selectedDay, onClick, historyDateList } = props;
const currentMonthText = currentMonth.format('YYYY.MM');
const dayMonthText = day.format('YYYY.MM');
if (currentMonthText !== dayMonthText) {
return <View className={styles.monthCell} />;
}
const todayText = dayjs().format('YYYY-MM-DD');
const dayText: string = day.format('YYYY-MM-DD');
const disable = day.isBefore(dayjs(), 'day');
const onHandleItem = (disable: boolean) => {
if (disable) {
return;
}
onClick && onClick(dayText);
};
return (
<View onClick={() => onHandleItem(disable)} className={styles.monthCell}>
<View
className={classnames(styles.monthCellValue, {
[styles.monthCellValueGrey]: disable,
[styles.monthCellValueToday]: todayText === dayText,
[styles.monthCellSelected]: selectedDay === dayText,
})}
>
{todayText === dayText ? '今' : day.format('D')}
</View>
{historyDateList.includes(dayText) && !disable && <View className={styles.monthCellPoint} />}
</View>
);
};
interface calenderProps {
onChangeMonth?: (val: dayjs.Dayjs) => void;
onChangeSelect?: (val: string) => void;
historyDateList?: string[];
focusDay?: string;
}
const CourseCalender = (props: calenderProps) => {
const {
onChangeSelect,
historyDateList = [],
onChangeMonth,
focusDay = dayjs().format('YYYY-MM-DD'),
} = props;
const today = dayjs().hour(0).minute(0).second(0).millisecond(0);
const todayMonth = today.clone().date(1);
const [currentMonth, setCurrentMonth] = useState(todayMonth);
const [selectedDay, setSelectedDay] = useState(focusDay);
const [showOneLine, setShowOneLine] = useState(true);
const hasPreMonth = todayMonth.isBefore(currentMonth);
const { weekList = [], selectedDayListIndex } = getWeekListByMonth(currentMonth, selectedDay);
const handlePreMonth = () => {
if (hasPreMonth) {
const preMonth = currentMonth.clone().subtract(1, 'month');
setCurrentMonth(preMonth);
onChangeMonth && onChangeMonth(preMonth);
// 切换月份日期默认全展示
setShowOneLine(false);
}
};
const handleNextMonth = () => {
const nextMonth = currentMonth.clone().add(1, 'month');
setCurrentMonth(nextMonth);
onChangeMonth && onChangeMonth(nextMonth);
// 切换月份日期默认全展示
setShowOneLine(false);
};
const onHandleMonthCell = (dayText: string) => {
setSelectedDay(dayText);
onChangeSelect && onChangeSelect(dayText);
};
const onHandleIcon = (showIcon: boolean) => {
if (!showIcon) {
return;
}
setShowOneLine(!showOneLine);
};
return (
<View className={styles.courseCalender}>
<View className={styles.calenderHead}>
<View className={styles.headLeft}>{currentMonth.format('YYYY年MM月')}</View>
<View className={styles.headRight}>
<View
className={classnames(styles.leftIcon, { [styles.leftIconGrey]: !hasPreMonth })}
onClick={handlePreMonth}
/>
<View
className={classnames(styles.rightIcon, { [styles.rightIconGrey]: false })}
onClick={handleNextMonth}
/>
</View>
</View>
<View className={styles.calenderContent}>
<View className={styles.calenderWeek}>
{weekdaysList.map((item, index) => (
<View className={styles.calenderWeekItem} key={index}>
{item}
</View>
))}
</View>
<View className={styles.calenderMonth}>
{(showOneLine ? [weekList[selectedDayListIndex]] : weekList).map(
(dayList, dayListIndex) => (
<View className={styles.calenderMonthRow} key={dayListIndex}>
{dayList.map(day => (
<MonthCell
key={day}
day={day}
currentMonth={currentMonth}
historyDateList={historyDateList}
selectedDay={selectedDay}
onClick={(dayText: string) => onHandleMonthCell(dayText)}
/>
))}
</View>
),
)}
</View>
</View>
<View
className={styles.calenderFooter}
onClick={() => onHandleIcon(currentMonth.format('YYYY-MM') == selectedDay.slice(0, 7))}
>
{currentMonth.format('YYYY-MM') == selectedDay.slice(0, 7) && (
<Image
className={styles.footerIcon}
webp
mode="aspectFill"
src={
showOneLine
? 'https://img.alicdn.com/imgextra/i3/O1CN015sI3l8283imvg6YPJ_!!6000000007877-2-tps-48-48.png'
: 'https://img.alicdn.com/imgextra/i4/O1CN01U8KCQe1DlINDEFEQq_!!6000000000256-2-tps-48-48.png'
}
lazyLoad
/>
)}
</View>
</View>
);
};
export default CourseCalender;
index.less
.courseCalender { width: 686px; background-color: #fff; border-radius: 8px; overflow: hidden; .calenderHead { width: 100%; height: 72px; background: #222; display: flex; flex-direction: row; justify-content: space-between; align-items: center; padding: 0 16px 0 24px; .headLeft { font-family: Akrobat-ExtraBold; font-size: 32px; color: #fff; } .headRight { display: flex; flex-direction: row; .leftIcon, .rightIcon { width: 48px; height: 48px; background-repeat: no-repeat; background-size: contain; margin-left: 8px; } .leftIcon { background-image: url('https://img.alicdn.com/imgextra/i2/O1CN01buoF9i1Ntfm2Xi8Vx_!!6000000001628-2-tps-48-48.png'); } .leftIconGrey { background-image: url('https://img.alicdn.com/imgextra/i2/O1CN01W9Cdbb29VUPwL5opO_!!6000000008073-2-tps-48-48.png'); } .rightIcon { background-image: url('https://img.alicdn.com/imgextra/i3/O1CN01lgfwCS1CE1zRUe9X7_!!6000000000048-2-tps-48-48.png'); } .rightIconGrey { background-image: url('https://img.alicdn.com/imgextra/i1/O1CN01INUsTs1zv0KCwndMy_!!6000000006775-2-tps-48-48.png'); } } } .calenderContent { width: 100%; padding: 0 12px; display: flex; flex-direction: column; align-items: center; .calenderWeek { width: 100%; height: 82px; display: flex; flex-direction: row; justify-content: space-around; align-items: center; .calenderWeekItem { width: 64px; height: 64px; font-family: PingFangSC-Regular; line-height: 64px; text-align: center; font-size: 22px; color: #666; flex-shrink: 0; } } .calenderMonth { width: 100%; .calenderMonthRow { width: 100%; height: 82px; display: flex; flex-direction: row; justify-content: space-around; align-items: center; } } } .calenderFooter { width: 100%; height: 48px; display: flex; align-items: center; justify-content: center; .footerIcon { width: 48px; height: 48px; } } } .monthCell { width: 64px; height: 64px; flex-shrink: 0; position: relative; .monthCellValue { width: 100%; height: 100%; font-family: PingFangSC-Regular; line-height: 64px; text-align: center; font-size: 32px; color: #666; border-radius: 50%; } .monthCellValueGrey { color: rgba(102, 102, 102, 0.3); } .monthCellValueToday { font-family: PingFangSC-Regular; font-size: 28px; color: #666; background-color: #f5f5f5; } .monthCellSelected { color: #f5f5f5; background-color: #ff6022; } .monthCellPoint { width: 8px; height: 8px; border-radius: 50%; background-color: #ff6022; position: absolute; bottom: 6px; left: 28px; } }

浙公网安备 33010602011771号