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

自定义Antd InputNumber组件:HH:MM转分钟及失焦问题求助

自定义Antd InputNumber组件问题排查与改进方案

问题原因分析

  • parser逻辑漏洞:用户输入过程中(如未输入冒号时),split(':')仅返回单个元素,parseInt(minutes)会得到NaN,导致返回值异常,触发组件重渲染失焦。
  • max值配置错误:当前max设为24/168(小时单位),但组件value存储的是分钟数,单位不匹配引发数值校验异常,导致组件状态混乱失焦。
  • value处理不当:currentValue || 0会将0转为0,但formatter处理0时返回空字符串,显示值与实际值不匹配,触发组件重渲染。
  • 字符串比较错误:parser中直接用字符串比较hours > 24,字符串按字符编码比较会出现逻辑错误(如"3">"24"会返回true),需转数字后再判断。

改进后的完整代码

import React from 'react'
import { Col, InputNumber, Row } from 'antd'

function MinutesInput({ value: currentValue, onChange, type = 'daily', ...props }) {
  const getMaxMinutes = () => {
    return type === 'daily' ? 24 * 60 : 168 * 60
  }

  return (
    <Row>
      <Col span={24}>
        <InputNumber
          className="w-100"
          min={0}
          max={getMaxMinutes()}
          formatter={(value) => {
            if (value === 0) {
              return '00:00'
            }
            if (!value) {
              return ''
            }
            const hours = Math.floor(value / 60)
            const minutes = value % 60
            return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}`
          }}
          parser={(value) => {
            if (!value) return 0
            // 处理输入过程中的不完整格式(如仅输入数字、未输入冒号)
            const parts = value.split(':')
            let hours = parseInt(parts[0]) || 0
            let minutes = parseInt(parts[1]) || 0

            // 分钟数限制在0-59之间
            minutes = Math.max(0, Math.min(59, minutes))
            // 小时数限制在对应类型的最大值内
            const maxHours = type === 'daily' ? 24 : 168
            hours = Math.max(0, Math.min(maxHours, hours))

            // 当小时等于最大值时,分钟强制设为0
            if (hours === maxHours) {
              minutes = 0
            }

            return hours * 60 + minutes
          }}
          value={currentValue ?? 0}
          addonAfter={currentValue !== undefined && currentValue !== 0 
            ? `${Math.floor(currentValue / 60)}h ${currentValue % 60}m` 
            : ''}
          onChange={onChange}
          {...props}
        />
      </Col>
    </Row>
  )
}

export default MinutesInput

关键优化点说明

  • 修正max值单位:将max改为分钟数(2460=1440、16860=10080),与value的存储单位一致,避免校验异常。
  • 完善parser容错逻辑:
    • 处理输入不完整的情况(如仅输入数字、无冒号),默认分钟为0,避免NaN。
    • 限制分钟在0-59之间,小时在对应类型的最大值内,当小时达到最大值时,分钟强制设为0(避免出现24:30这种非法值)。
    • 将字符串转为数字后再进行大小比较,避免字符串比较的逻辑错误。
  • 优化value与formatter的一致性:
    • 用currentValue ?? 0替代currentValue || 0,避免0被错误覆盖。
    • formatter处理0时返回"00:00",保证显示与值的一致性,避免组件状态混乱。
    • 用padStart(2, '0')统一格式为两位数字,提升用户体验。
  • 优化addonAfter显示:当currentValue为0或undefined时,不显示附加文本,避免冗余信息。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 18:20:27