Ant Design InputNumber 格式化展示实战:formatter 与 parser 完整指南
2026/9/19 9:05:18 网站建设 项目流程

Ant Design InputNumber 格式化展示实战:formatter 与 parser 完整指南

【免费下载链接】ant-designAn enterprise-class UI design language and React UI library项目地址: https://gitcode.com/gh_mirrors/ant/ant-design

InputNumber 是 Ant Design 组件库(components/input-number)中的数据录入组件,用于通过鼠标或键盘输入范围内的数值。在真实业务中,我们常常需要让数字以「有具体含义」的形式呈现——比如货币金额带千分位逗号和货币符号、百分比数值带%后缀。本指南围绕官方演示 formatter.tsx 展开,讲解如何用formatter定制展示格式、用parser将格式化后的文本解析回数值,并深入 API 细节与底层实现,帮助你写出可直接落地于表单、报表等场景的格式化数字输入框。

formatter 与 parser:展示层与数值层的双向桥

Ant Design 的 InputNumber 内部维护着「真实数值」与「展示文本」两层状态:

  • formatterfunction(value: number | string, info: { userTyping: boolean, input: string }): string,负责把内部数值转换成输入框中展示的字符串。它只影响展示,不改变组件内部保存的真实值。
  • parserfunction(string): number,负责把用户输入(或格式化后的字符串)解析回原始数值,与formatter成对使用。没有parser时,格式化的文本无法被正确还原为数字。

二者必须保证「互逆」:parser(formatter(value))应能还原出原始数值。官方文档对两者的定位非常明确——「通过formatter格式化数字,以展示具有具体含义的数据,往往需要配合parser一起使用」(见 index.zh-CN.md)。

从源码看,Ant Design 的 InputNumber 是对rc-input-number的封装(index.tsx),formatterparser均通过{...others}透传给底层组件(index.tsx),因此在类型签名上直接继承了RcInputNumberProps的定义。

完整示例:货币格式化与百分比格式化

官方演示 formatter.tsx 在同一页面展示了两个最典型的场景:千分位货币百分比。以下为完整代码:

import React from 'react'; import type { InputNumberProps } from 'antd'; import { InputNumber, Space } from 'antd'; const onChange: InputNumberProps['onChange'] = (value) => { console.log('changed', value); }; const App: React.FC = () => ( <Space> <InputNumber<number> defaultValue={1000} formatter={(value) => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')} parser={(value) => value?.replace(/\$\s?|(,*)/g, '') as unknown as number} onChange={onChange} /> <InputNumber<number> defaultValue={100} min={0} max={100} formatter={(value) => `${value}%`} parser={(value) => value?.replace('%', '') as unknown as number} onChange={onChange} /> </Space> ); export default App;

场景一:货币金额(千分位 +$符号)

defaultValue={1000}时,输入框展示为$ 1,000。这段代码是面试级经典正则在真实组件中的落地:

  • formatter:先拼接$前缀,再通过\B(?=(\d{3})+(?!\d))在整数部分每三位插入逗号。该正则利用「零宽断言」在非单词边界\B)处匹配「后面跟着 1 组或多组恰好 3 位数字、且这 3 位数字之后不再紧跟数字」的位置,从而实现千分位分隔,且不影响小数部分。
  • parser:用\$\s?匹配可选的$与空白、用(,*)匹配所有逗号,一并替换为空,把$ 1,000还原成1000
  • 类型断言:由于parser返回类型为number,示例通过as unknown as number完成类型收敛;配合泛型<number>声明,onChange回调中的value也获得精确的类型提示。

场景二:百分比(%后缀 + 范围约束)

defaultValue={100}min={0}max={100}时,输入框展示为100%

  • formatter:模板字符串直接追加%后缀。
  • parservalue?.replace('%', '')去掉后缀即还原数值。
  • 范围约束min/max保证通过步进按钮(默认step=1)增减时不会越界;onChange打印的是还原后的真实数值。

验证:快照测试中的格式化结果

组件库自带快照测试 demo.test.tsx.snap 完整记录了该演示的渲染结果。以第一个输入框为例,快照中可见:

<input aria-valuenow="1000" class="ant-input-number-input" role="spinbutton" step="1" value="$ 1,000" />

这说明底层<input>元素的value是格式化后的展示文本$ 1,000,而aria-valuenow仍保留真实数值1000——这正是「展示层与数值层分离」的直观证据,也解释了为何必须通过onChange(而非读取 DOM)获取真实值。第二个百分比输入框的增减按钮因min/max边界而带有ant-input-number-handler-up-disabled等禁用态类名,同样可在快照中印证。

API 深度解析:formatter、parser 及其关联配置

根据组件文档 index.zh-CN.md 的 API 表格,与格式化能力直接相关的参数如下:

参数说明类型默认值版本
formatter指定输入框展示值的格式function(value: number \| string, info: { userTyping: boolean, input: string }): string-info: 4.17.0
parser指定从formatter里转换回数字的方式,和formatter搭配使用function(string): number--
precision数值精度,配置formatter时会以formatter为准number--
decimalSeparator小数点string--
stringMode字符值模式,开启后支持高精度小数,onChange返回 string 类型booleanfalse4.13.0
value / defaultValue当前值 / 初始值number--
onChange变化回调function(value: number \| string \| null)--

需要特别留意的三点:

  1. formatter 的第二参info(4.17.0+){ userTyping: boolean, input: string }用于区分当前是用户输入中还是失焦格式化。典型用法是「输入过程中不打断用户、失焦后才应用格式」——例如仅当!info.userTyping时插入千分位,避免输入时光标跳动。input字段则为用户当前输入的原始字符串。
  2. precision 与 formatter 的优先级:官方文档明确「配置formatter时会以formatter为准」。也就是说,如果你同时设置了precision={2}和自定义formatter,精度舍入逻辑将被formatter的返回结果覆盖,格式化职责完全交由你的函数掌控。
  3. onChange 的取值约定onChange拿到的是parser 还原后的真实数值number | string | null),而onBlur等事件中event.target.value只是 DOM 的展示字符串。官方 FAQ 对此有专门说明(index.zh-CN.md):例如通过formatterdecimalSeparator更改展示格式后,DOM 中得到的就是格式化后的字符串,「你总是应该通过onChange获取当前值」。这也意味着onBlur里做校验、取数等逻辑时需要改用onChange

底层原理:格式化在组件中的实际流转

从实现角度看,整个格式化链路如下:

  1. 属性透传:Ant Design 的 InputNumber 在 index.tsx 中构造RcInputNumber元素,将formatterparserminmaxstepprecision等未被解构的属性经{...others}全部透传给rc-input-number,自身不干预数值逻辑。
  2. 展示层rc-input-number内部对<input>value应用formatter,所以输入框渲染的是格式化字符串(快照中value="$ 1,000"即由此产生),同时通过aria-valuenow等属性暴露真实数值。
  3. 解析层:用户编辑、步进按钮增减、失焦回写时,parser把展示文本还原为数值,再参与min/max钳制与onChange回调,保证表单收集到的是干净的数字。
  4. 事件取值:由于onBlur等原生事件直接暴露 DOM 字符串,官方 FAQ 建议一律以onChange作为取数入口(index.en-US.md)。

进阶实践建议

  • 与 Form 搭配onChange是受控取数的唯一可靠入口,配合Form.Itemnamerules做必填、范围校验,parser返回的数值即为提交值。
  • 国际化货币decimalSeparator可自定义小数点符号;如需按 locale 动态生成千分位与货币符号,可自行封装一个工厂函数返回formatter/parser对,保持「先 format 后 parse 互逆」的原则。
  • 输入体验优化:利用info.userTyping在输入过程中返回原始文本、仅在失焦时格式化,避免正则替换导致光标跳动;若仍出现光标异常,可考虑聚焦时临时展示原始数值。
  • 避免原生 type 冲突:不要在组件上额外传type="number",否则 input 会触发原生数值输入特性(如滚轮改值),干扰格式化后的文本展示与changeOnWheel行为(见 index.zh-CN.md 的 FAQ 说明)。

通过以上方案,你可以在 Ant Design 的 InputNumber 上快速实现货币、百分比、计量单位等带语义的数值输入,同时保证提交数据的准确与可控。

【免费下载链接】ant-designAn enterprise-class UI design language and React UI library项目地址: https://gitcode.com/gh_mirrors/ant/ant-design

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询