提问前先看看:
https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/main/README-zh_CN.md
🐛 bug 描述
ProFormDigit 设置 min/max 后,某些超出范围的值在 onBlur 时不会被收窄(clamp),行为不一致。
max 场景(max={999}):
- 输入
1234 → onBlur 后收窄到 999 ✅
- 输入
99999 → onBlur 后保持 99999 ❌
min 场景(min={100}):
- 输入
56 → onBlur 后收窄到 100 ✅
- 输入
10 → onBlur 后保持 10 ❌
📷 复现步骤
- 使用
<ProFormDigit max={999} min={1} fieldProps={{ precision: 0 }} />
- 在输入框中输入
99999
- 点击空白处(触发 onBlur)
- 观察输入框的值和表单值仍为 99999,未收窄到 999
🏞 期望结果
输入任意超出 min/max 范围的值,onBlur 后都应统一收窄到边界值。
💻 复现代码
CodeSandbox: https://codesandbox.io/s/tjplnz
© 版本信息
- ProComponents 版本: 3.1.12-0
- antd 版本: 6.3.3
- 浏览器环境: Chrome
- 开发环境: macOS
🚑 其他信息
根因分析:
问题出在 packages/field/src/components/Digit/index.tsx 中 FieldDigit 的自定义 onBlur 与 rc-input-number 原生 clamp 逻辑的竞争:
- FieldDigit 用
omit(fieldProps, ['onChange', 'onBlur']) 移除了 InputNumber 原始的 onChange/onBlur,替换为自定义版本
- 自定义 onBlur 中通过
proxyChange(e.target.value) 处理值后直接调用 fieldProps.onChange(),但 proxyChange 只做字符串转数字和 precision 处理,不做 min/max clamp
- 之后
rc-input-number 的 onBlur(绑定在外层 <div>,通过事件冒泡触发)会尝试 clamp,但其 triggerValueUpdate 中有去重逻辑:当 clamp 后的值等于内部 decimalValue 时,会跳过 onChange
不一致的具体原因:
以 max=999 为例:
- 输入
1234:逐字输入的中间值为 1→12→123→1234,最后一个 ≤ 999 的中间值是 123,clamp 后 999 ≠ 123 → onChange 正常触发 ✅
- 输入
99999:中间值为 9→99→999→9999→99999,最后一个 ≤ 999 的中间值恰好是 999,clamp 后 999 === 999 → 触发去重,onChange 被跳过 ❌
min 同理:clamp 是否生效取决于「输入序列中最后一个在 [min, max] 范围内的中间值」是否恰好等于边界值。
相关 issue:#9048(ProFormDigitRange 的同源问题,已通过 #9058 修复,但该修复不涉及 ProFormDigit 的 FieldDigit)
提问前先看看:
https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/main/README-zh_CN.md
🐛 bug 描述
ProFormDigit设置min/max后,某些超出范围的值在 onBlur 时不会被收窄(clamp),行为不一致。max 场景(
max={999}):1234→ onBlur 后收窄到 999 ✅99999→ onBlur 后保持 99999 ❌min 场景(
min={100}):56→ onBlur 后收窄到 100 ✅10→ onBlur 后保持 10 ❌📷 复现步骤
<ProFormDigit max={999} min={1} fieldProps={{ precision: 0 }} />99999🏞 期望结果
输入任意超出 min/max 范围的值,onBlur 后都应统一收窄到边界值。
💻 复现代码
CodeSandbox: https://codesandbox.io/s/tjplnz
© 版本信息
🚑 其他信息
根因分析:
问题出在
packages/field/src/components/Digit/index.tsx中 FieldDigit 的自定义onBlur与rc-input-number原生 clamp 逻辑的竞争:omit(fieldProps, ['onChange', 'onBlur'])移除了 InputNumber 原始的 onChange/onBlur,替换为自定义版本proxyChange(e.target.value)处理值后直接调用fieldProps.onChange(),但proxyChange只做字符串转数字和 precision 处理,不做 min/max clamprc-input-number的 onBlur(绑定在外层<div>,通过事件冒泡触发)会尝试 clamp,但其triggerValueUpdate中有去重逻辑:当 clamp 后的值等于内部decimalValue时,会跳过 onChange不一致的具体原因:
以
max=999为例:1234:逐字输入的中间值为1→12→123→1234,最后一个 ≤ 999 的中间值是123,clamp 后999 ≠ 123→ onChange 正常触发 ✅99999:中间值为9→99→999→9999→99999,最后一个 ≤ 999 的中间值恰好是999,clamp 后999 === 999→ 触发去重,onChange 被跳过 ❌min 同理:clamp 是否生效取决于「输入序列中最后一个在 [min, max] 范围内的中间值」是否恰好等于边界值。
相关 issue:#9048(ProFormDigitRange 的同源问题,已通过 #9058 修复,但该修复不涉及 ProFormDigit 的 FieldDigit)