- 前端
- UI组件
- 设计系统
【免费下载链接】semi-design
🚀A modern, comprehensive, flexible design system and React UI library, AI-friendly built-in.🎨Provide 3000+ Design Tokens, easy to build your design system. Make Semi Design to Any Design.🧑🏻💻 Design to Code in one click
本文围绕 Semi Design 组件库的InputNumber数字输入框展开,系统讲解其引入方式、步进器交互(step/shiftStep/innerButtons/长按连发)、formatter/parser自定义格式化、currency国际化货币展示与scientificNotation科学计数法显示等核心能力,并结合 packages/semi-ui/inputNumber/index.tsx 与 packages/semi-foundation/inputNumber/foundation.ts 的源码实现,说明各配置项背后的真实工作机制。读完本文,你将能够在 Semi 项目中熟练实现带范围约束、格式化展示、货币/多语言与超长数字场景的数字输入方案。
组件定位与引入
InputNumber是 Semi Design 提供的数字输入组件,与普通Input的区别在于:它面向“数值”场景内置了步进器(上/下按钮)操作区,同时通过parser与formatter的配合,可以展示比纯数字更复杂的内容格式(如千分位货币、自定义分隔串等)。完整示例与 API 说明见文档 content/input/inputnumber/index.md。
从组件库中直接引入即可使用:
import { InputNumber } from '@douyinfe/semi-ui';组件在semi-ui包中的实现入口为 packages/semi-ui/inputNumber/index.tsx,它通过forwardStatics包裹React.forwardRef,并默认套上一层LocaleConsumer,因此InputNumber会自动感知全局LocaleProvider的语言环境(locale),这也是货币模式默认值的重要前提。
基础用法:步长、范围、默认值与精度
最简用法与常用属性组合
import React from 'react'; import { InputNumber } from '@douyinfe/semi-ui'; () => ( <div style={{ width: 280 }}> <label>简单数字输入框</label> <InputNumber /> <br/><br/> <label>设置了步长 step=2 </label> <InputNumber step={2} /> <br/><br/> <label>设置 shiftStep=100,按住 shift 同时点击按钮,可以一次增加/减少100 </label> <InputNumber shiftStep={100} /> <br/><br/> <label>设置了上下界 min=1,max=10</label> <InputNumber min={1} max={10} defaultValue={1} /> <br/><br/> </div> );import React from 'react'; import { InputNumber } from '@douyinfe/semi-ui'; () => ( <div style={{ width: 280 }}> <label>设置了默认值 defaultValue=1 </label> <InputNumber defaultValue={1} /> <br/><br/> <label>禁用 disabled=true</label> <InputNumber defaultValue={2} disabled /> <br/><br/> <label>设置了小数位数 precision=2 </label> <InputNumber precision={2} defaultValue={1.234} /> <br/><br/> <label>设置了 innerButtons=true </label> <InputNumber innerButtons={true} suffix={'小时'} defaultValue={1} style={{ width: 190 }} /> <br/> </div> );关键属性的默认值与边界
依据 packages/semi-foundation/inputNumber/constants.ts 与 index.tsx 中的defaultProps,各核心参数的默认值如下:
| 属性 | 默认值 | 说明 |
|---|---|---|
step | 1 | 每次点击/按键改变的量,可为小数 |
shiftStep | 10(v2.13 起由1调整为10) | 按住 Shift 时每次改变的量,可为小数 |
min/max | -Infinity/Infinity | 数值上下界,不传则不受限 |
precision | 无 | 小数精度,传入后会在解析/失焦时对数值做toFixed(precision)处理 |
pressTimeout | 250(毫秒) | 长按按钮时,延迟多久后开始连发 |
pressInterval | 250(毫秒) | 长按按钮时,连发阶段的触发间隔 |
注意:
DEFAULT_PRESS_INTERVAL在 constants.ts 中定义为0,而组件defaultProps中pressInterval取的是numbers.DEFAULT_PRESS_TIMEOUT(即 250);foundation 中_registerInterval读取 prop 失败时才回退到DEFAULT_PRESS_INTERVAL。实际效果以 props 传入值为准,不传即 250ms。
边界约束的底层实现
min/max的约束并不是仅在点击按钮时生效:在 foundation.ts 中,fetchMinOrMax会在解析(doParse)与格式化(doFormat)阶段对数值做钳制;add/minus计算步进结果时,也会先判断“当前值距离边界是否仍大于等于步长”,避免越界(foundation.ts)。isValidNumber(foundation.ts)则要求数值同时满足「类型为 number 且非 NaN」「在[min, max]区间内」「小数位数不超过precision」三个条件才算合法。
步进器控制:innerButtons、hideButtons 与长按连发
两种隐藏步进器的方式
innerButtons将步进器收纳进输入框内部,仅在 hover 时显示,适合追求紧凑界面的场景:
import React from 'react'; import { InputNumber } from '@douyinfe/semi-ui'; () => ( <InputNumber innerButtons style={{ width: 190 }} /> );hideButtons设为true则彻底隐藏步进器:
import React from 'react'; import { InputNumber } from '@douyinfe/semi-ui'; () => ( <InputNumber hideButtons style={{ width: 190 }} /> );从源码看,这两者共用同一套步进按钮渲染逻辑 index.tsx:innerButtons模式下按钮作为suffix渲染,且仅当hovering && !focusing时展示(renderSuffix中判断innerButtons && (hovering || focusing));hideButtons或innerButtons为真时,外层不再渲染独立按钮区域。
长按连发与 keepFocus
步进按钮支持按住连续触发:handleUpClick/handleDownClick在触发一次后,会通过_registerTimer(延迟pressTimeout)再注册_registerInterval(间隔pressInterval)实现持续步进;松开鼠标(handleMouseUp)或移出按钮时注销定时器(foundation.ts)。这两个时间参数即上表 API 中的pressTimeout/pressInterval。
keepFocus用于点击步进按钮时保持输入框焦点不丢失(适合需要连续调整数值、又不希望触发失焦逻辑的场景)。测试用例(packages/semi-ui/inputNumber/test/inputNumber.test.js)中也有keepFocus与按钮点击组合的受控模式验证。
尺寸
size支持"default"、"large"、"small"三种取值,控制输入框整体高度,内部通过semi-input-{size}类名生效:
import React from 'react'; import { InputNumber } from '@douyinfe/semi-ui'; () => ( <div style={{ width: 180 }}> <label>默认尺寸 size=default</label> <InputNumber /> <br/><br/> <label>大尺寸 size=large</label> <InputNumber size="large" /> <br/><br/> <label>小尺寸 size=small</label> <InputNumber size="small" /> <br/> </div> );formatter 与 parser:自定义显示格式与解析
成对使用是前提
formatter决定“输入框里展示成什么样子”,parser决定“从展示串还原出数字串”,两者一般需要同时设置,否则无法正确解析值。示例中通过onChange打印值的实际类型与内容,方便观察解析结果:
import React from 'react'; import { InputNumber } from '@douyinfe/semi-ui'; () => { const log = (v) => { console.log(`Changed to: [${typeof v}] ${v}`); }; return ( <div style={{ width: 180 }}> <label>人民币</label> <InputNumber onChange={this.log} defaultValue={1000} min={0} formatter={value => `¥ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')} parser={value => value.replace(/\¥\s?|(,*)/g, '')} /> <br/><br/> <label>自定义串</label> <InputNumber onChange={this.log} defaultValue={1111} formatter={value => String(value).split('').join('-')} parser={value => value.replace(/\-/g, '')} /> <br/> </div> ); };第一个示例演示千分位货币串(1,000),第二个演示自定义分隔串(1-1-1-1)。注意两个示例都同时提供了配套的parser将展示串还原为纯数字,否则格式化后的字符串无法被正确解析回数值。
2.95.0 行为调整:受控模式首帧即应用 formatter
官方文档特别提示了 2.95.0 的行为变更(见 content/input/inputnumber/index.md):
- 2.94.0 及之前:当
InputNumber处于受控模式(传入value)且value为number时,首次渲染阶段输入框的展示值可能不会先经过formatter处理,组件会在 mount 后(或后续更新)再应用formatter/parser,从而出现首帧展示与后续不一致的现象。 - 2.95.0 及之后:受控模式下当
value为number时,首次渲染也会应用formatter(并与parser配合得到内部数值),保证首帧展示与后续一致。例如百分比场景:value=1且formatter/parser使展示乘以 100 时,首帧将直接展示100。
这一修复与 index.tsx 中constructor里通过_getInitState初始化 state 的实现直接相关——初始化时若传入的是 number,会先调用foundation.doFormat格式化、再doParse得到内部数值,从而保证首帧即经过 formatter 处理。
纯数字输入框(v1.9.0+)
搭配formatter和onNumberChange(>= v1.9.0)可以实现“只允许纯数字”的输入框:formatter将非数字字符过滤掉,onNumberChange拿到过滤后的 number 值:
import React from 'react'; import { InputNumber } from '@douyinfe/semi-ui'; function Demo () { return ( <InputNumber formatter={value => `${value}`.replace(/\D/g, '')} onNumberChange={number => console.log(number)} min={0} max={Number.MAX_SAFE_INTEGER} /> ); }这里的
min/max设置了0到Number.MAX_SAFE_INTEGER的合法区间,防止过滤后的空串或非法值被当作合法数字处理。
formatter/parser 在源码中的调用链
在 foundation.ts 中:
doFormat(value, needAdjustPrec, needAdjustCurrency)(L638-L667)负责“数字 → 展示串”:先做精度调整/货币格式化,再在最后套用formatter。doParse(value, needCheckPrec, needAdjustPrec, needAdjustMaxMin)(L709-L771)负责“展示串 → 数字”:先调用parser还原,再做精度、范围钳制与科学计数法解析。- 用户输入的每一帧都会经过
handleInputChange(L191-L258):非法字符会被 parser 过滤后重新格式化展示,保证“所有输入都经过 parser 和 format 处理”;失焦时handleInputBlur会再次校验并格式化为规范展示。
货币展示(2.77.0+)
国际化模式:currency={true}
自2.77.0起支持货币展示。国际化模式下通过currency={true}开启,组件会根据LocaleProvider的locale自动展示对应货币种类。以下示例内置了 20+ 语言切换,切换语言类型后需要更新组件key值(示例中使用key={localeCode})以强制重建组件、刷新货币符号:
import React, { useCallback, useMemo, useState } from 'react'; import zh_CN from '@douyinfe/semi-ui/lib/es/locale/source/zh_CN'; import en_GB from '@douyinfe/semi-ui/lib/es/locale/source/en_GB'; import en_US from '@douyinfe/semi-ui/lib/es/locale/source/en_US'; import ko_KR from '@douyinfe/semi-ui/lib/es/locale/source/ko_KR'; import ja_JP from '@douyinfe/semi-ui/lib/es/locale/source/ja_JP'; import ar from '@douyinfe/semi-ui/lib/es/locale/source/ar'; import vi_VN from '@douyinfe/semi-ui/lib/es/locale/source/vi_VN'; import ru_RU from '@douyinfe/semi-ui/lib/es/locale/source/ru_RU'; import id_ID from '@douyinfe/semi-ui/lib/es/locale/source/id_ID'; import ms_MY from '@douyinfe/semi-ui/lib/es/locale/source/ms_MY'; import th_TH from '@douyinfe/semi-ui/lib/es/locale/source/th_TH'; import tr_TR from '@douyinfe/semi-ui/lib/es/locale/source/tr_TR'; import pt_BR from '@douyinfe/semi-ui/lib/es/locale/source/pt_BR'; import zh_TW from '@douyinfe/semi-ui/lib/es/locale/source/zh_TW'; import sv_SE from '@douyinfe/semi-ui/lib/es/locale/source/sv_SE'; import pl_PL from '@douyinfe/semi-ui/lib/es/locale/source/pl_PL'; import nl_NL from '@douyinfe/semi-ui/lib/es/locale/source/nl_NL'; import es from '@douyinfe/semi-ui/lib/es/locale/source/es'; import it from '@douyinfe/semi-ui/lib/es/locale/source/it'; import de from '@douyinfe/semi-ui/lib/es/locale/source/de'; import fr from '@douyinfe/semi-ui/lib/es/locale/source/fr'; import ro from '@douyinfe/semi-ui/lib/es/locale/source/ro'; import { LocaleProvider, InputNumber, Select } from '@douyinfe/semi-ui'; function I18nDemo() { const [locale, setLocale] = useState(zh_CN); const [localeCode, setLocaleCode] = useState('zh_CN'); const language = useMemo(() => ({ 'zh_CN': zh_CN, 'en_GB': en_GB, 'en_US': en_US, 'ko_KR': ko_KR, 'ja_JP': ja_JP, 'ar': ar, 'vi_VN': vi_VN, 'ru_RU': ru_RU, 'id_ID': id_ID, 'ms_MY': ms_MY, 'th_TH': th_TH, 'tr_TR': tr_TR, 'pt_BR': pt_BR, 'zh_TW': zh_TW, 'es': es, 'sv_SE': sv_SE, 'pl_PL': pl_PL, 'nl_NL': nl_NL, de, it, fr, ro }), []); const onLanguageChange = (code) => { setLocale(language[code]); setLocaleCode(code); }; return ( <> <div style={{ paddingBottom: 20 }}> <Select onChange={onLanguageChange} insetLabel='切换语言' style={{ width: 250 }} defaultValue='zh_CN'> <Select.Option value='zh_CN'>简体中文</Select.Option> <Select.Option value='en_US'>英语(美)</Select.Option> <Select.Option value='en_GB'>英语(英)</Select.Option> <Select.Option value='ja_JP'>日语</Select.Option> <Select.Option value='ko_KR'>韩语</Select.Option> <Select.Option value='ar'>阿拉伯语</Select.Option> <Select.Option value='vi_VN'>越南语</Select.Option> <Select.Option value='ru_RU'>俄罗斯语</Select.Option> <Select.Option value='id_ID'>印尼语</Select.Option> <Select.Option value='ms_MY'>马来语</Select.Option> <Select.Option value='th_TH'>泰语</Select.Option> <Select.Option value='tr_TR'>土耳其语</Select.Option> <Select.Option value='pt_BR'>葡萄牙语(巴西)</Select.Option> <Select.Option value='zh_TW'>繁体中文</Select.Option> <Select.Option value='es'>西班牙语</Select.Option> <Select.Option value='de'>德语</Select.Option> <Select.Option value='it'>意大利语</Select.Option> <Select.Option value='fr'>法语</Select.Option> <Select.Option value='ro'>罗马尼亚语</Select.Option> <Select.Option value='sv_SE'>瑞典语</Select.Option> <Select.Option value='pl_PL'>波兰语</Select.Option> <Select.Option value='nl_NL'>荷兰语</Select.Option> </Select> </div> <LocaleProvider locale={locale}> <InputNumber key={localeCode} currency={true} defaultValue={123456.78} /> </LocaleProvider> </> ); }手动指定 localeCode 与 currency
也可以手动传localeCode和currency直接指定展示的货币种类,不依赖全局 Locale:
import React from 'react'; import { InputNumber } from '@douyinfe/semi-ui'; () => { const defaultValue = 123456.78; return ( <div> <div>🇨🇳 人民币</div> <InputNumber localeCode="zh-CN" currency="CNY" defaultValue={defaultValue} /> <br /> <br /> <div>🇪🇺 欧元</div> <InputNumber localeCode="de-DE" currency="EUR" defaultValue={defaultValue} /> <br /> <br /> <div>🇯🇵 日元</div> <InputNumber localeCode="ja-JP" currency="JPY" defaultValue={defaultValue} /> <br /> <br /> <div>🇻🇳 越南盾</div> <InputNumber localeCode="vi-VN" currency="VND" defaultValue={defaultValue} /> <br /> <br /> </div> ); };currencyDisplay 三种展示方式与 showCurrencySymbol
支持symbol(货币符号,默认)、code(货币代码)、name(货币名称)三种展示方式,通过currencyDisplay属性控制:
import React from 'react'; import { InputNumber } from '@douyinfe/semi-ui'; () => { const defaultValue = 123456.78; return ( <div> <div>🇨🇳 CNY ➕ code</div> <InputNumber currency="CNY" currencyDisplay="code" defaultValue={defaultValue} /> <br /> <br /> <div>🇨🇳 CNY ➕ symbol</div> <InputNumber currency="CNY" currencyDisplay="symbol" defaultValue={defaultValue} /> <br /> <br /> <div>🇨🇳 CNY ➕ name</div> <InputNumber currency="CNY" currencyDisplay="name" defaultValue={defaultValue} /> <br /> <br /> </div> ); };showCurrencySymbol设置为false可以隐藏货币符号/代码/名称的展示,此时通常配合prefix/suffix自行展示货币标识:
import React from 'react'; import { InputNumber } from '@douyinfe/semi-ui'; () => { const defaultValue = 123456.78; return ( <div> <div>🇨🇳 CNY ➕ code</div> <InputNumber style={{ width: 200 }} currency="CNY" prefix="CNY" showCurrencySymbol={false} defaultValue={defaultValue} /> <br /> <br /> <div>🇨🇳 CNY ➕ symbol</div> <InputNumber style={{ width: 200 }} currency="CNY" prefix="¥" showCurrencySymbol={false} defaultValue={defaultValue} /> <br /> <br /> <div>🇨🇳 CNY ➕ name</div> <InputNumber style={{ width: 200 }} currency="CNY" suffix="人民币" showCurrencySymbol={false} defaultValue={defaultValue} /> <br /> <br /> </div> ); };货币模式的底层实现
货币展示依赖浏览器原生Intl.NumberFormat:formatCurrency(foundation.ts)用style: 'currency'格式化数值,并支持minimumFractionDigits/maximumFractionDigits(可回退到precision);_setCurrencySymbol则通过formatToParts提取当前 locale 下的小数点符号与货币符号(foundation.ts),供parseInternationalCurrency将货币串还原为纯数字。
getCurrencyByLocaleCode(foundation.ts)内置了一张地区码 → 货币码映射表(如zh-CN → CNY、ja-JP → JPY、de-DE → EUR、en-US → USD等),未命中时按语言前缀回退(en → USD、zh → CNY),最后兜底USD。测试用例(packages/semi-ui/inputNumber/test/inputNumber.test.js)覆盖了 CNY/USD/EUR/JPY/VND/THB/IDR 等常见货币及showCurrencySymbol={false}、currencyDisplay三种展示方式的格式化结果。
科学计数法显示(2.97.0+)
当数字较长时,可通过scientificNotation属性启用科学计数法显示:失去焦点时显示科学计数法,获得焦点时显示完整数字。默认阈值为 15 位有效数字,也可传入对象自定义阈值:
import React from 'react'; import { InputNumber } from '@douyinfe/semi-ui'; () => { return ( <div style={{ width: 280 }}> <label>启用科学计数法(默认阈值 15 位)</label> <InputNumber scientificNotation defaultValue={123456789012345} /> <br /><br /> <label>自定义阈值(10 位)</label> <InputNumber scientificNotation={{ threshold: 10 }} defaultValue={1234567890} /> <br /><br /> <label>超大数字</label> <InputNumber scientificNotation defaultValue={9999999999999999} /> <br /><br /> <label>小数场景</label> <InputNumber scientificNotation precision={10} defaultValue={0.000000123456789} /> <br /><br /> </div> ); };注意事项(文档原文明确声明):
科学计数法仅影响显示格式,
onChange和onNumberChange回调中的值仍为完整数字。该功能不支持货币模式(currency)。
在源码层面,_getScientificNotationThreshold(foundation.ts)读取scientificNotation.threshold,默认 15;_toScientificNotation(foundation.ts)统计有效数字位数(排除小数点、正负号、指数符号与前导零),超过阈值时用num.toExponential()生成科学计数法串并去掉系数尾部多余的零;doFormat仅在“失焦展示态”(needAdjustCurrency=true且非货币模式)下应用科学计数法;handleInputFocus在聚焦时检测到科学计数法串(形如1.23e+15)会还原为完整数字再展示(foundation.ts)。doParse中也内置了对科学计数法字符串(如"1.23e+15"、"1.23E-10")的解析支持。
API 参考
以下为 content/input/inputnumber/index.md 中完整 API 表,并结合源码补充了默认值与版本信息:
| 属性 | 说明 | 类型 | 默认值 | 版本 |
|---|---|---|---|---|
| autofocus | 自动获取焦点 | boolean | false | |
| className | 类名 | string | - | |
| clearIcon | 自定义清除按钮,showClear 为 true 时有效 | ReactNode | - | 2.25.0 |
| currency | 货币种类,国际化模式下通过currency={true}开启,组件自动根据 locale 展示对应货币;也可手动传入localeCode和currency指定。可选值如CNY、EUR、USD等 | boolean|string | false | 2.77.0 |
| currencyDisplay | 货币展示方式:symbol、code、name | string | symbol | 2.77.0 |
| defaultValue | 默认值 | number | - | |
| disabled | 禁用 | boolean | false | |
| formatter | 指定输入框展示值的格式 | (value: number|string) => string | - | |
| hideButtons | 为true时隐藏"上/下"按钮 | boolean | false | |
| innerButtons | 为true时"上/下"按钮显示在输入框内部 | boolean | false | |
| keepFocus | 点击按钮时保持输入框聚焦 | boolean | false | |
| localeCode | 货币模式下指定国家地区代码,可选值如zh-CN、en-US、en-GB、ja-JP、ko-KR、ar、vi-VN、ru-RU、id-ID、ms-MY、th-TH、tr-TR、pt-BR、zh-TW、es、de、it、fr、ro、sv-SE、pl-PL、nl-NL等 | string | - | 2.77.0 |
| max | 限定最大值 | number | Infinity | |
| min | 限定最小值 | number | -Infinity | |
| parser | 指定从formatter里转换回数字串的方式,和formatter搭配使用 | (str: string) => string | - | |
| precision | 数值精度 | number | - | |
| prefix | 前缀内容 | string|ReactNode | - | |
| pressInterval | 长按按钮时,多久触发一次点击事件(毫秒) | number | 250 | |
| pressTimeout | 长按按钮时,延迟多久后触发点击事件(毫秒) | number | 250 | |
| preventScroll | 指示浏览器是否应滚动文档以显示新聚焦的元素,作用于组件内的 focus 方法 | boolean | - | |
| scientificNotation | 启用科学计数法显示:失焦显示科学计数法、聚焦显示完整数字。可传对象配置阈值threshold,默认 15 位有效数字。不支持货币模式 | boolean|{ threshold?: number } | false | 2.97.0 |
| shiftStep | 按住 shift 键每次改变步数,可为小数,v2.13 默认值由 1 调整为 10 | number | 10 | |
| showClear | 是否显示清除按钮 | boolean | false | |
| showCurrencySymbol | 是否显示货币符号/代码/名称,仅货币模式下生效 | boolean | true | 2.77.0 |
| size | 输入框大小:"default"|"small"|"large" | string | 'default' | |
| step | 每次改变步数,可以为小数 | number | 1 | |
| style | 样式 | CSSProperties | - | |
| suffix | 自定义后缀 | ReactNode | - | |
| value | 当前值(受控) | number | - | |
| onBlur | 失去焦点时的回调 | (e: domEvent) => void | () => {} | |
| onChange | 变化回调 | (value: number|string) => void | - | |
| onFocus | 获得焦点时的回调 | (e: domEvent) => void | () => {} | |
| onNumberChange | 数字变化回调(纯数字场景,>= v1.9.0) | (value: number) => void | - |
补充说明:组件内部还暴露了
onUpClick(value, e)/onDownClick(value, e)两个步进按钮点击回调(见 index.tsx 的 Props 类型),可在需要感知步进方向时使用。onChange与onNumberChange的差异在于:onChange可能回传格式化后的字符串或数字,onNumberChange仅在有意义的数值变化时回传 number(notifyNumberChange会过滤掉非显著变化,见 foundation.ts)。
Methods
以下方法绑定在组件实例上,可通过ref调用实现某些特殊交互:
| 名称 | 描述 |
|---|---|
| blur() | 移出焦点 |
| focus() | 获取焦点 |
使用示例(ref 同时支持对象与函数两种形式,测试用例中有对应验证):
import React, { useRef } from 'react'; import { InputNumber } from '@douyinfe/semi-ui'; function Demo() { const ref = useRef(null); return ( <> <InputNumber ref={ref} /> <button onClick={() => ref.current.focus()}>聚焦</button> <button onClick={() => ref.current.blur()}>失焦</button> </> ); }Accessibility:无障碍与键盘交互
参考标准:W3C WAI-ARIA APG 的 spinbutton 模式(https://www.w3.org/WAI/ARIA/apg/patterns/spinbutton/)。
ARIA
- 数字输入框具有spinbuttonrole;
- spinbutton 使用
aria-valuenow表示当前值,aria-valuemax表示可接受的最大值,aria-valuemin表示可接受的最小值; - 当
InputNumber在Form中使用时,输入框的aria-labelledby指向 Field label。
以上语义在源码渲染层有直接体现:组件向内部Input传入role="spinbutton",并仅在number存在时设置aria-valuenow、在max !== Infinity时设置aria-valuemax、在min !== -Infinity时设置aria-valuemin(index.tsx)。
键盘和焦点
InputNumber可被获取焦点,键盘用户可以使用 Tab 及 Shift + Tab 切换焦点(增加/减少按钮不可以被键盘聚焦);- 键盘用户可以按上键 ⬆️ 或下键 ⬇️,输入值将增加或减少
step(默认值为 1); - 按住 Shift + 上键 ⬆️ 或下键 ⬇️,输入值将增加或减少
shiftStep(默认值为 10)。
键盘上下键的响应在handleInputKeyDown中实现(foundation.ts):检测到 UP/DOWN 键码后,分别调用add/minus计算新值,再通过_doInput更新并触发onChange,同时event.preventDefault()阻止输入框内光标跳动。Shift 的判定在add/minus中通过event.shiftKey完成(foundation.ts),按 Shift 时使用shiftStep,否则使用step。
与 Form 表单的配合
InputNumber可在Form中作为字段使用,测试代码(packages/semi-ui/inputNumber/test/inputNumber.test.js)中引入了Form、withField、useFormApi进行联动验证。在Form.Field中直接放置InputNumber即可获得校验、label 关联(aria-labelledby)与取值能力,适合数量、金额、百分比等数值型表单字段。
总结
InputNumber是 Semi Design 中面向数值输入场景的高频组件,核心能力可归纳为四点:
- 步进交互:
step/shiftStep控制增减粒度,innerButtons/hideButtons控制步进器形态,pressTimeout/pressInterval支持长按连发; - 格式化解析:
formatter与parser成对使用实现任意展示格式,2.95.0 起受控模式首帧即应用 formatter; - 国际化货币:2.77.0 起基于
Intl.NumberFormat与 locale 映射实现多语言货币展示,currencyDisplay、showCurrencySymbol精细控制展示形式; - 长数字场景:2.97.0 起的
scientificNotation让超长数字在失焦时以科学计数法呈现、聚焦时还原完整数值。
配合onNumberChange、min/max/precision约束与完整的 ARIA/键盘无障碍支持,InputNumber可以覆盖从基础数值输入到复杂货币格式化的绝大多数业务场景。所有能力的实现细节均可追溯至 packages/semi-ui/inputNumber/index.tsx 与 packages/semi-foundation/inputNumber/foundation.ts,读者可结合源码进一步深入。
- 前端
- UI组件
- 设计系统
【免费下载链接】semi-design
🚀A modern, comprehensive, flexible design system and React UI library, AI-friendly built-in.🎨Provide 3000+ Design Tokens, easy to build your design system. Make Semi Design to Any Design.🧑🏻💻 Design to Code in one click
相关推荐
PrimeNG InputNumber 组件完全指南:数字输入、货币格式化与 Angular 表单集成
PrimeNG InputNumber 组件完全指南:数字输入、货币格式化与 Angular 表单集成 InputNumber 是 PrimeNG 提供的数值输
前端UI组件antd InputNumber 数字输入框完全指南:API 精讲、高精度小数、格式化展示与边界场景排查
antd InputNumber 数字输入框完全指南:API 精讲、高精度小数、格式化展示与边界场景排查 导读:本文以 ant design 仓库中 compo
前端UI组件设计系统Excel 自定义数字格式:百分比、货币与科学计数法设置
Excel 自定义数字格式:百分比、货币与科学计数法设置 在日常数据处理中,Excel 数字格式的正确设置能让数据更具可读性和专业性。无论是财务报表中的货币格式
后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考