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

ReactJS日期输入框:如何根据月份动态限制日期最大值?

问题分析与修复方案

你的代码存在几个关键问题,导致动态日期限制功能未生效,以下是具体问题和修复步骤:

1. maxDayInMonth 函数逻辑错误

  • 第一个条件分支错误使用了未定义的 setMaxDay = 28,应改为 return 28;
  • 闰年判断不严谨,未考虑整百年需被400整除才是闰年的规则(比如1900年不是闰年,2000年是);
  • 输入的月份/年份是字符串类型,直接和数字比较会出现类型不匹配(比如 "2" === 2 结果为 false)。

修正后的函数:

const maxDayInMonth = (monthStr, yearStr) => {
  const month = Number(monthStr);
  const year = Number(yearStr);
  
  // 未输入月份/年份时返回默认最大值,避免报错
  if (!month || !year) return 31;

  // 标准闰年判断逻辑
  const isLeapYear = (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;

  if (month === 2) {
    return isLeapYear ? 29 : 28;
  } else if ([4, 6, 9, 11].includes(month)) {
    return 30;
  } else {
    return 31;
  }
};

2. 未正确管理表单状态

你提到了 useState 但代码中没有定义和更新 formData 的状态,导致月份/年份变化时,组件不会重新计算日期输入框的 max 属性。

添加状态定义并修正 handleChange:

const [formData, setFormData] = useState({
  dob_day: '',
  dob_month: '',
  dob_year: ''
});

const handleChange = (e) => {
  const value = e.target.type === "checkbox" ? e.target.checked : e.target.value;
  const name = e.target.name;
  // 更新表单状态,触发组件重新渲染
  setFormData(prev => ({ ...prev, [name]: value }));

  // 当月份/年份变化时,手动触发日期输入框的HTML5校验
  if (name === 'dob_month' || name === 'dob_year') {
    const dayInput = document.getElementById('dob_day');
    dayInput?.checkValidity();
  }
};

3. 确保HTML5校验生效

HTML5默认只会在表单提交或输入框失去焦点时校验,当 max 值动态变化后,需要手动调用 checkValidity() 触发校验,上面的 handleChange 中已经添加了这部分逻辑。

完整修复后的代码

import { useState } from "react";
import { useCookies } from 'react-cookie';
import { useNavigate } from "react-router-dom";
import axios from "axios";

const YourComponent = () => {
  const [formData, setFormData] = useState({
    dob_day: '',
    dob_month: '',
    dob_year: ''
  });
  const [cookies, setCookie] = useCookies();
  const navigate = useNavigate();

  const handleChange = (e) => {
    const value = e.target.type === "checkbox" ? e.target.checked : e.target.value;
    const name = e.target.name;
    setFormData(prev => ({ ...prev, [name]: value }));

    // 触发日期输入框校验
    if (name === 'dob_month' || name === 'dob_year') {
      const dayInput = document.getElementById('dob_day');
      dayInput?.checkValidity();
    }
  };

  const maxDayInMonth = (monthStr, yearStr) => {
    const month = Number(monthStr);
    const year = Number(yearStr);
    
    if (!month || !year) return 31;

    const isLeapYear = (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;

    if (month === 2) {
      return isLeapYear ? 29 : 28;
    } else if ([4, 6, 9, 11].includes(month)) {
      return 30;
    } else {
      return 31;
    }
  };

  const minYear = new Date().getFullYear() - 100;
  const maxYear = new Date().getFullYear() - 18;

  return (
    <>
      <input
        id="dob_day"
        type="number"
        name="dob_day"
        placeholder="DD"
        min="1"
        max={maxDayInMonth(formData.dob_month, formData.dob_year)}
        required={true}
        value={formData.dob_day}
        onChange={handleChange}
      />
      <input
        id="dob_month"
        type="number"
        name="dob_month"
        placeholder="MM"
        min="1"
        max="12"
        required={true}
        value={formData.dob_month}
        onChange={handleChange}
      />
      <input 
        id="dob_year"
        type="number"
        name="dob_year"
        placeholder="YYYY"
        min={minYear}
        max={maxYear}
        required={true}
        value={formData.dob_year}
        onChange={handleChange}
      />
    </>
  );
};

export default YourComponent;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 16:20:46