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

基于验证状态的DatePicker动态边框颜色实现方案

实现带动态边框颜色的受控日期输入框(react-datepicker + react-input-mask)

需求规则

  • 默认状态:边框使用初始颜色#9095A1,无阴影
  • 聚焦状态:输入框为空时,边框变为紫色,添加紫色阴影
  • 无效状态:输入内容不完整、格式错误或未填写时,边框变为红色,添加红色阴影
  • 有效状态:输入内容为合法日期时,边框变为绿色,添加绿色阴影

优化实现代码

import { useState } from 'react';
import { Controller } from 'react-hook-form';
import DatePicker from 'react-datepicker';
import InputMask from 'react-input-mask';
import { parse, format, isValid } from 'date-fns';

const ControlledDateInput = ({
  control,
  name,
  disabled = false,
  placeholder = 'MM/DD/YYYY',
  minDate,
  maxDate,
  IconLeft,
  IconRight
}) => {
  const [isFocused, setIsFocused] = useState(false);

  return (
    <Controller
      control={control}
      name={name}
      rules={{
        validate: (value) => {
          if (!value) return 'Date is required';
          const cleanedValue = value.replace(/_/g, '').trim();
          if (cleanedValue.length < 10) return 'Incomplete date';
          const parsedDate = parse(cleanedValue, 'MM/dd/yyyy', new Date());
          if (!isValid(parsedDate)) return 'Invalid date format';
          return true;
        },
      }}
      render={({ field, fieldState }) => {
        // 判断是否无效:验证错误、内容不完整、包含占位符下划线
        const isInvalid = fieldState.error || 
                          field.value.includes('_') || 
                          field.value.length < 10;
        
        // 计算边框颜色和阴影
        let borderColor = '#9095A1';
        let boxShadow = 'none';
        
        if (isFocused && !field.value) {
          // 聚焦且为空的状态
          borderColor = 'purple';
          boxShadow = '0 0 5px purple';
        } else if (isInvalid) {
          // 无效状态
          borderColor = 'red';
          boxShadow = '0 0 5px rgb(201,23,23)';
        } else if (field.value) {
          // 有效状态
          borderColor = 'green';
          boxShadow = '0 0 5px rgb(40,224,24)';
        }

        return (
          <span
            className={`input ${isInvalid ? 'error' : field.value ? 'valid' : ''}`}
            style={{ borderColor, boxShadow }}
          >
            {IconLeft && <span className="icon">{IconLeft}</span>}

            <DatePicker
              disabled={disabled}
              shouldCloseOnSelect={true}
              placeholderText={placeholder}
              selected={
                field.value.length === 10
                  ? parse(field.value, 'MM/dd/yyyy', new Date())
                  : null
              }
              minDate={minDate}
              maxDate={maxDate}
              onChange={(date) => {
                const formattedDate = date ? format(date, 'MM/dd/yyyy') : '';
                field.onChange(formattedDate);
              }}
              customInput={
                <InputMask
                  mask="99/99/9999"
                  value={field.value || ''}
                  onChange={(e) => field.onChange(e.target.value)}
                  onFocus={() => setIsFocused(true)}
                  onBlur={() => {
                    setIsFocused(false);
                    // 清空不完整的日期
                    if (field.value.includes('_') || field.value.length < 10) {
                      field.onChange('');
                    }
                  }}
                  disabled={disabled}
                />
              }
            />

            {IconRight && <span className="icon">{IconRight}</span>}
          </span>
        );
      }}
    />
  );
};

export default ControlledDateInput;

关键优化说明

  1. 状态驱动聚焦样式:用useState维护isFocused状态,替代直接操作DOM样式,符合React状态驱动的设计理念
  2. 集中样式计算:把边框颜色和阴影的判断逻辑集中处理,避免在多个事件回调中重复编写样式代码,提升代码可维护性
  3. 精准无效状态判断:结合react-hook-form的验证错误、输入内容长度和占位符下划线,全面覆盖无效场景
  4. 状态视图同步:在失焦时自动清空不完整日期,确保表单状态和输入框内容一致

内容的提问来源于stack exchange,提问作者David Gyulinyan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 05:43:23