用react对antd的Calendar组件进行二次封装,用于显示当月时间的某一天是否存在某种状态。

154 阅读1分钟

需求:由于项目需要antd的Calendar组件配合去显示当前月份的每一天是否存在录像,用橘色圆点进行标注,具体如图。

image.png

代码如下

import { IconFont, useSimpleState } from '@cloud-app-dev/vidc';
import { getMonthDate } from '@src/Service/videoApi';
import { Badge, Calendar } from 'antd';
import dayjs, { Dayjs } from 'dayjs';
import React, { FC, ReactElement, useEffect, useState } from 'react'

interface IPropsType {

}

const MyCalendar: FC<IPropsType> = (): ReactElement => {

  const [date, setDate] = useSimpleState({ date: dayjs() });
  const [timestamps, setTimestamps] = useState<{ begin: number, end: number }[]>([])

  //用于监听当Calendar组件的月份时间变化时,调用接口请求当月的时间内具体某一天是否存在录像
  useEffect(() => {
    const data = {
      begin: date.date.startOf('month').unix(),
      end: date.date.endOf('month').unix(),
    }
    getMonthDate(data).then((res) => {
      setTimestamps(res.data?.timeline)
    })
  }, [date])


  //用于判断当天的时间戳是否存在接口返回的时间戳数组中,用于日期下橘色圆点的显隐状态
  const isTimestampWithinRanges = (timestamp: number, ranges: { begin: number, end: number }[]) => {
    for (const r of ranges) {
      if (timestamp >= r.begin && timestamp <= r.end) {
        return true;
      }
    }
    return false;
  }


  return (
    <Calendar
      fullscreen={false}
      className="calendar-select-box"
      value={date.date}
      disabledDate={(v: Dayjs) => (dayjs(new Date()).diff(v) < 0)}
      //自定义头部内容
      headerRender={({ value }) => {
        return (
          <div className="header">
            <div className="pre" onClick={() => setDate({ date: value.clone().add(-1, 'M') })}>
              <IconFont type="icon-renwupeizhi_shebeirenwu_shouqi" />
            </div>
            <div className="months">{value.format('YYYY-MM')}</div>
            <div className="next" onClick={() => setDate({ date: value.clone().add(1, 'M') })}>
              <IconFont type="icon-renwupeizhi_shebeirenwu_shouqi-copy" />
            </div>
          </div>
        );
      }}
      //自定义渲染日期单元格
      dateFullCellRender={(date) => (
        //用antd的Badge组件来显示橘色圆点
        <Badge dot={isTimestampWithinRanges(date.unix(), timestamps)} color='#F29219' offset={[-10, 22]} >
          <span
            className={`cloudapp-picker-cell-inner cloudapp-picker-calendar-date ${date.format('YYYY-MM-DD') === dayjs(new Date()).format('YYYY-MM-DD') && 'cloudapp-picker-calendar-date-today'
              }`}
          >
            <span className="cloudapp-picker-calendar-date-value">{date.format('YYYY-MM-DD') === dayjs(new Date()).format('YYYY-MM-DD') ? '今' : date.format('DD')}</span>
          </span>
        </Badge>
      )}
    />
  )
}

export default MyCalendar

其中的useSimpleState是对react的useState进行的二次封装,代码如下

import { useMemoizedFn, useSafeState } from 'ahooks';
import { isFunction, isObjectLike } from 'lodash-es';
import React, { useMemo } from 'react';

function useSimpleState<T>(s: T) {
  const [state, setState] = useSafeState(s);
  const stateChange = useMemoizedFn((d: Partial<T>) => setState((old) => ({ ...old, ...d })));
  // eslint-disable-next-line react-hooks/exhaustive-deps
  const isObject = useMemo(() => isObjectLike(s) || (isFunction(s) && isObjectLike(s())), []);

  const result = useMemo(
    () => [state, isObject ? stateChange : setState, setState] as [T, (data: Partial<T>) => void, React.Dispatch<React.SetStateAction<T>>],
    [isObject, setState, state, stateChange],
  );
  return result;
}

export default useSimpleState;

主要作用为在使用uesState返回的set方法去更新一个对象中的某个值时不需要再去通过函数的形式去修改,可以直接使用useSimpleState返回的stateChange去更新值,例如stateChange({a:1})