Smart Input 格式化合集
同一套 createSmartInput 在五个场景下的用法:千分位数字(动态 min / max)、时分秒 strict 守门、6 位 OTP(镜像格子 + 智能 paste)、多 tag chip 输入,以及 IME-safe 的 Enter 提交。history / IME / DOM 适配都由 smart-input 接管,调用方只需描述一个 Formatter。引擎本身的管线剖析见
Smart Input 引擎,领域专属 DSL 的渐进式输入另见 规则输入框。
1 · 千分位数字输入
允许 0-9 / . / -;normalize 阶段把 1234567 自动加千分位逗号,变成 1,234,567;多余的 . 与位置不对的 - 会被丢弃。可选 min / max 上下界,越界时 validate 返回 invalid
并显示具体提示;留空表示无限制。
试试:打 12345678.9 → 实时变成 12,345,678.9;输入 1.2.3 → 第二个 . 被吞;ctrl/cmd+z 撤销;含非法字符的剪贴板被整段拒绝;在 min / max 里填 0 与 10000 → 当前值 1,234,567.89 越上界立即变 invalid。
2 · 时分秒(HH:MM:SS)
仅允许 0-9 / :;strict + isExtendable 守门:小时段 ≤ 23,分秒段 ≤ 59(输 25 开头会直接被吞);段一满就补 :(光标落在 : 之后);段首位不可能当十位时自动补零(时 3→03,分秒
6→06)。
试试:打 143025 → 实时变成 14:30:25;打小时 3 → 立即变 03:,分秒 6 → 06;输 25 开头 → 字符被拒(没有 25 字头的合法小时);删掉自动补的 : → 连它前面那位数字一起删(不被卡住)。
3 · 验证码(6 位)
仅允许数字;normalize 截到 6 位;pill 实时显示进度 N / 6。视觉上是 6 个独立格子,但底层仍是一个 <input>(透明铺在格子上层接管键入 / 光标 / 粘贴),6 个格子只镜像值。额外加了自定义 paste 处理:粘贴「Your code is 654321, valid for 5 min」这种带前后文的短信内容时,自动抽出 6
位数字填入。
试试:直接打 6 位数字;粘贴 Your code is 654321 → 自动抽出 654321 填入;输入非数字字符 → beforeinput 拦截(闪红)。autocomplete="one-time-code" 让浏览器从短信中识别建议码。
4 · 多 tag 输入
chip 数组 + 末尾单 input 的业界标准结构(Ant Design Select.tags / Mantine TagsInput / Material UI Autocomplete 都是这种模型)。chip 是原子 DOM 节点,不可半删半编辑。smart-input 在这里只负责「那一个末尾 input」的单 tag 校验(字符过滤、长度上限、重名提示)。
UX:Enter 或分隔符 → 提交当前输入为 chip;空 input 上 Backspace → 删尾 chip;chip 上 × → 单独删除;点 chip 任意空白 → 聚焦回 input;输入框失焦也会自动提交。重名会被 invalid 拒掉(尝试再次添加 react 看效果)。
5 · IME-safe submit · Enter 提交
聊天框式的「Enter 提交」。日文 / 中文用户靠 IME 边输入边按 Enter 确认候选词,若应用在合成期间就把 Enter 当提交,会造成「输入途中被发送」。本 demo 在 keydown 里用 isImeComposingKey(e) 守门——合成中(isComposing 或 Safari 的 keyCode === 229)直接放行,让 IME 自己处理那次
Enter;只有非合成的 Enter 才真正提交。
要点:合成期间 keydown 命中 isImeComposingKey 即 return(不 preventDefault,让 IME 接管那次 Enter)。纯提交场景更推荐直接用 <form> 的 submit 事件(浏览器原生处理,连 Safari bug 都绕过);这里演示的是必须自接 keydown 的情形。