软件教程 2025年08月6日
0 收藏 0 点赞 587 浏览 5660 个字
摘要 :

文章目录 实现效果 实现方式 先定义时间选项 引入相关依赖 实现组件布局 加上事件处理选择时间后的逻辑 支持受控模式和非受控模式 本文主要讲解关于React 实现 cron ……




  • 实现效果
  • 实现方式
    • 先定义时间选项
    • 引入相关依赖
    • 实现组件布局
    • 加上事件处理选择时间后的逻辑
    • 支持受控模式和非受控模式

    本文主要讲解关于React 实现 cron 时间选择器组件相关内容,让我们来一起学习下吧!

    cron 是最常见的类 Unix 系统下的基于时间的任务管理系统,在实现定时任务场景中较常使用。

    本文介绍适合实现一个前端时间选择组件,其中绑定的值使用 cron 的时间格式,方便传递给后端存储使用。

    实现效果

    React 实现 cron 时间选择器组件

    实现方式

    先定义时间选项

    export enum TimeType {
      EVERY_DAY = \"everyDay\",
      EVERY_WEEK = \"everyWeek\",
      EVERY_MONTH = \"everyMonth\",
    }
    
    export const timeTypes = [
      { value: TimeType.EVERY_DAY, label: \"每天\" },
      { value: TimeType.EVERY_WEEK, label: \"每周\" },
      { value: TimeType.EVERY_MONTH, label: \"每月\" },
    ];
    
    export const dayOfTheWeekOption = [
      { value: \"1\", label: \"星期一\" },
      { value: \"2\", label: \"星期二\" },
      { value: \"3\", label: \"星期三\" },
      { value: \"4\", label: \"星期四\" },
      { value: \"5\", label: \"星期五\" },
      { value: \"6\", label: \"星期六\" },
      { value: \"7\", label: \"星期天\" },
    ];
    
    export const monthOption = [
      { value: \"1\", label: \"一月\" },
      { value: \"2\", label: \"二月\" },
      { value: \"3\", label: \"三月\" },
      { value: \"4\", label: \"四月\" },
      { value: \"5\", label: \"五月\" },
      { value: \"6\", label: \"六月\" },
      { value: \"7\", label: \"七月\" },
      { value: \"8\", label: \"八月\" },
      { value: \"9\", label: \"九月\" },
      { value: \"10\", label: \"十月\" },
      { value: \"11\", label: \"十一月\" },
      { value: \"12\", label: \"十二月\" },
    ];
    
    //获取dayOfTheMonthOption的每月对象
    function getDayOfTheMonthOption() {
      const days = [];
      for (let i = 1; i < 32; i += 1) {
        days.push({ value: i.toString(), label: i.toString().concat(\"号\") });
      }
      return days;
    }
    
    export const dayOfTheMonthOption = getDayOfTheMonthOption();
    
    export function parseCron(expression: string) {
      const cron = expression ? expression.split(\" \") : [];
      const [minutes, hours, dayOfMonth, month, dayOfWeek] = cron;
      // \"20 0 * * *\" 每天
      // \"26 1 * * 1\" 每周
      // \"26 0 1 * *\" 每月
      const isEveryDay = dayOfMonth === \"*\" && month === \"*\" && dayOfWeek === \"*\";
      const isEveryWeek = dayOfMonth === \"*\" && month === \"*\" && dayOfWeek !== \"*\";
      const isEveryMonth = dayOfMonth !== \"*\" && month === \"*\" && dayOfWeek === \"*\";
      return {
        isEveryDay,
        isEveryWeek,
        isEveryMonth,
        cron,
        cronObjects: { minutes, hours, dayOfMonth, month, dayOfWeek },
      };
    }
    

    引入相关依赖

    这里使用 Ant Design 组件库,使用 dayjs 处理时间

    import { Select, Space, TimePicker } from \"antd\";
    import type { Dayjs } from \"dayjs\";
    import dayjs from \"dayjs\";
    import { useEffect, useState } from \"react\";
    import {
      TimeType,
      dayOfTheMonthOption,
      dayOfTheWeekOption,
      timeTypes,
      parseCron,
    } from \"./utils\";
    

    实现组件布局

    这里我们需要三种时间类型选择,分为每天、每周、每月,每个时间类型选择都需要选择时间,其中每周需要选择周几,每月需要选择几号。

    使用下拉组件实现时间类型选择和周几、几号选择,使用时间选择器组件实现时间选择。

    const format = \"HH:mm\";
    const defaultCron = \"0 * * * *\";
    const space = \" \"; //空格
    
    type CronInputProps = {
      value?: string;
      onChange?: (cron: string) => void;
    };
    
    const CronInput: React.FC<CronInputProps> = (props) => {
      const [timeType, setTimeType] = useState(TimeType.EVERY_DAY); // 类型
      const [selectedDay, setSelectedDay] = useState<string>(); // 日期(星期几或者几号)
      const [selectedTime, setSelectedTime] = useState<Dayjs | null>(null); // 时间
      const [expression, setExpression] = useState<string>(defaultCron);
    
      const RenderSelect = ({
        placeholder,
        data = [],
      }: {
        placeholder: string;
        data: { value: string; label: string }[];
      }) => {
        return (
          <Space>
            <Select
              placeholder={placeholder}
              onChange={handleChangeSelectedDay}
              value={selectedDay}
              options={data}
            ></Select>
            <TimePicker
              value={selectedTime}
              format={format}
              placeholder=\"请选择时间\"
              onChange={handleChangeTime}
            />
          </Space>
        );
      };
    
      return (
        <Space>
          <Select
            placeholder=\"请选择类型\"
            onChange={handleChangeTimeType}
            value={timeType}
            options={timeTypes}
          ></Select>
          {timeType === TimeType.EVERY_DAY && (
            <TimePicker
              value={selectedTime}
              format={format}
              placeholder=\"请选择时间\"
              onChange={handleChangeTime}
            />
          )}
          {timeType === TimeType.EVERY_WEEK && (
            <RenderSelect data={dayOfTheWeekOption} placeholder=\"请选择星期\" />
          )}
          {timeType === TimeType.EVERY_MONTH && (
            <RenderSelect data={dayOfTheMonthOption} placeholder=\"请选择日期\" />
          )}
        </Space>
      );
    };
    

    加上事件处理选择时间后的逻辑

    时间类型改变,重置周几和日期选择、重置时间选择

    周几和日期选择,时间选择事件中,将选中的数据处理转换成 cron 格式中的位数

      // 类型选择
      const handleChangeTimeType = (val: TimeType) => {
        setTimeType(val);
        setSelectedTime(null);
        setSelectedDay(undefined);
        handleChange(defaultCron);
      };
    
      // 日期选择
      const handleChangeSelectedDay = (day: string) => {
        setSelectedDay(day);
        const currentCron = expression ? expression.split(\" \") : [];
        const [minutes, hours, dayOfMonth, month, dayOfWeek] = currentCron;
        let result = \"\";
        if (timeType === TimeType.EVERY_WEEK) {
          result = minutes
            .concat(space)
            .concat(hours)
            .concat(space)
            .concat(dayOfMonth)
            .concat(space)
            .concat(month)
            .concat(space)
            .concat(day);
        }
        if (timeType === TimeType.EVERY_MONTH) {
          result = minutes
            .concat(space)
            .concat(hours)
            .concat(space)
            .concat(day.length ? day : \"*\")
            .concat(space)
            .concat(month)
            .concat(space)
            .concat(dayOfWeek);
        }
        if (result) {
          handleChange(result);
        }
      };
    
      //时间选择
      const handleChangeTime = (time: Dayjs | null) => {
        setSelectedTime(time);
        if (!time) return;
        const currentCron = expression ? expression.split(\" \") : [];
        const [, , dayOfMonth, month, dayOfWeek] = currentCron;
        const minutes = time.minute().toString(); //获取分钟
        const hours = time.hour().toString(); //获取小时
        let result = undefined;
        if (!Number.isNaN(Number(hours)) && !Number.isNaN(Number(minutes))) {
          const minutesAndHour = minutes.concat(space).concat(hours).concat(space);
          if (timeType === TimeType.EVERY_DAY)
            result = minutesAndHour.concat(\"* * *\");
          if (timeType !== TimeType.EVERY_DAY)
            result = minutesAndHour
              .concat(dayOfMonth)
              .concat(space)
              .concat(month)
              .concat(space)
              .concat(dayOfWeek);
        }
        if (result) {
          handleChange(result);
        }
      };
    

    支持受控模式和非受控模式

    React 组件通常都支持受控模式和非受控模式,按照约定,通过 valueonChange 事件来使组件成为受控模式,这样把状态从父组件传入可以在父组件中轻松拿到具体数值

      const { value = defaultCron, onChange } = props;
    
      // 这里需要判断如果存在 value,转换对应的状态支持组件回显
      useEffect(() => {
        if (value && value !== expression) {
          setExpression(value);
          const { isEveryDay, isEveryWeek, isEveryMonth, cron } = parseCron(value);
          const [minutes, hours, dayOfMonth, , dayOfWeek] = cron;
          const nextTimeType = isEveryDay
            ? TimeType.EVERY_DAY
            : isEveryWeek
            ? TimeType.EVERY_WEEK
            : isEveryMonth
            ? TimeType.EVERY_MONTH
            : timeTypes[0].value;
          setTimeType(nextTimeType);
    
          if (isEveryWeek) {
            setSelectedDay(dayOfWeek);
          }
          if (isEveryMonth) {
            setSelectedDay(dayOfMonth);
          }
    
          if (!Number.isNaN(Number(hours)) && !Number.isNaN(Number(minutes))) {
            setSelectedTime(dayjs(`${hours}:${minutes}`, format));
          }
        }
      }, [value]);
    

    部分代码参考自掘金文章,去除了秒数和支持受控组件

    以上就是关于React 实现 cron 时间选择器组件相关的全部内容,希望对你有帮助。欢迎持续关注潘子夜个人博客(www.panziye.com),学习愉快哦!

微信扫一扫

支付宝扫一扫

版权: 转载请注明出处:https://www.zuozi.net/6639.html

管理员

相关推荐
2025-08-06

文章目录 一、Promise基础回顾 二、Promise 与 axios 结合使用场景及方法 (一)直接返回 axios …

269
2025-08-06

文章目录 一、模块初始化时的内部机制 二、常见导出写法的差异分析 (一)写法一:module.exports…

107
2025-08-06

文章目录 一、ResizeObserver详解 (一)ResizeObserver是什么 (二)ResizeObserver的基本用法 …

683
2025-08-06

文章目录 一、前期准备工作 (一)下载相关文件 (二)安装必要工具 二、处理扣子空间生成的文件…

338
2025-08-06

文章目录 一、官方文档 二、自动解包的数据类型 ref对象:无需.value即可访问 reactive对象:保持…

371
2025-08-06

文章目录 一、Hooks的工作原理 二、在if语句中使用Hook会出什么岔子? 三、React官方的Hook使用规…

843
发表评论
暂无评论

还没有评论呢,快来抢沙发~

助力内容变现

将您的收入提升到一个新的水平

点击联系客服

在线时间:08:00-23:00

客服QQ

122325244

客服电话

400-888-8888

客服邮箱

122325244@qq.com

扫描二维码

关注微信客服号