You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React DatePicker自定义输入框手动输入格式化验证问题

React DatePicker自定义输入框的手动输入验证与格式化方案

你当前的问题在于handleChangeRaw直接将输入框值替换为startDate的格式化结果——而startDate状态还未同步用户的实时输入,导致用户输入的内容被立刻覆盖,自然无法正常输入。以下是可行的解决方案:

核心思路

  1. 实时过滤用户输入:只保留数字字符,避免非日期相关的随意输入
  2. 自动格式化输入内容:在输入过程中自动插入/,匹配dd/MM/yyyy格式
  3. 验证日期合法性:仅当输入的内容能解析为有效日期时,才更新组件的selected状态

完整代码实现

import { useState, useRef, forwardRef } from "react";
import DatePicker from "react-datepicker";
import { format, parse, isValid } from "date-fns";
import "react-datepicker/dist/react-datepicker.css";

const CustomInput = forwardRef<HTMLInputElement, any>((props, ref) => {
  return <input {...props} ref={ref} />;
});

export default function App() {
  const [startDate, setStartDate] = useState<Date | null>(null);
  const inputRef = useRef<HTMLInputElement>(null);

  // 处理输入内容的格式化与验证
  const formatInputDate = (inputValue: string) => {
    // 过滤所有非数字字符
    const cleaned = inputValue.replace(/\D/g, "");
    // 按dd/MM/yyyy格式拼接,自动插入斜杠
    let formatted = "";
    if (cleaned.length >= 2) {
      formatted += cleaned.slice(0, 2) + "/";
    } else {
      formatted += cleaned;
    }
    if (cleaned.length >= 4) {
      formatted += cleaned.slice(2, 4) + "/";
    } else if (cleaned.length > 2) {
      formatted += cleaned.slice(2);
    }
    if (cleaned.length > 4) {
      formatted += cleaned.slice(4, 8);
    }
    return formatted;
  };

  const handleChangeRaw = (e: React.FormEvent<HTMLInputElement>) => {
    const inputValue = e.currentTarget.value;
    const formattedValue = formatInputDate(inputValue);
    // 更新输入框显示的格式化内容
    e.currentTarget.value = formattedValue;

    // 当输入内容长度符合dd/MM/yyyy时,尝试解析为日期
    if (formattedValue.length === 10) {
      const parsedDate = parse(formattedValue, "dd/MM/yyyy", new Date());
      if (isValid(parsedDate)) {
        setStartDate(parsedDate);
      }
    }
  };

  return (
    <div className="App">
      <DatePicker
        selected={startDate}
        customInput={<CustomInput ref={inputRef} />}
        onChangeRaw={handleChangeRaw}
        onChange={(date: Date | null) => {
          setStartDate(date);
        }}
        dateFormat="dd/MM/yyyy"
      />
    </div>
  );
}

关键说明

  • 输入过滤与格式化:formatInputDate函数会先过滤掉所有非数字字符,再根据输入长度自动插入/,让用户输入过程中自动贴合目标格式。
  • 日期验证:当输入内容长度达到10位(完整的dd/MM/yyyy格式)时,使用date-fns的parse和isValid验证日期合法性,只有有效日期才更新startDate状态。
  • 状态同步:onChange仍保留处理日历选择的逻辑,onChangeRaw专注处理手动输入的格式化与验证,两者互不冲突。

内容的提问来源于stack exchange,提问作者Alex T

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 17:27:30