DirectSurface UIDirectSurface UI
开始使用
文档/组件手册

MaskedTextEdit 固定格式输入

通用布局能力RenderMaskedTextEdit 支持 widthheight、min/max、margin 和槽位对齐;fieldHeight 只控制输入主体高度。详见组件通用布局属性

RenderMaskedTextEdit 用于录入结构固定、但不参与数值运算的文本,例如病案号、固定长度编号、电话号码和自定义业务编码。

它在 RenderTextBox 的输入、选区、粘贴和 IME 会话之上增加 MaskEngine。业务保存的是不含分隔符的 raw value,界面绘制的是包含固定字符的 display value。

API 总览

主类:

  • RenderMaskedTextEdit
  • MaskEngine

相关 public type:

  • RenderMaskedTextEditOptions
  • MaskTokenDefinition
  • MaskTokenDefinitions
  • MaskValue
  • MaskEditResult

导入:

import {  MaskEngine,  RenderMaskedTextEdit,  type MaskTokenDefinitions,  type MaskValue,} from 'ds-ui'

何时使用

适合:

  • 病案号、就诊号、设备编号等固定格式字符串。
  • 电话号码、邮政编码等需要自动插入分隔符的字段。
  • 只允许数字、字母或字母数字组合的业务编码。
  • 需要业务自定义字符规则和大小写转换的输入。

不适合:

  • 普通自由文本,使用 TextField
  • 需要数值运算、范围和步进的字段,使用 NumberInput
  • 日期、时间和持续时长,分别使用 DatePickerTimeEditTimeSpanEdit
  • 格式会根据上下文大幅变化,或者需要在同一字段中任意跳过中间段的输入。这类规则应由专用编辑器承担。

最小示例

import { RenderMaskedTextEdit } from 'ds-ui' const patientState = {  phone: '',} const phone = new RenderMaskedTextEdit({  mask: '000-0000-0000',  value: patientState.phone,  placeholder: '输入手机号',  clearable: true,  onChange: (value, details) => {    patientState.phone = value    console.log(details.display, details.complete)  },})

输入 13800138000 后:

phone.value        // '13800138000'
phone.displayValue // '138-0013-8000'
phone.complete     // true

值模型

组件同时维护两种值:

示例 用途
raw value '13800138000' value、业务状态和回调的第一参数,不包含 mask 固定字符。
display value '138-0013-8000' displayValue 和界面文本,包含自动插入的固定字符。

构造参数和运行时属性 value 都接收 raw value。写入时会:

  1. 按 mask 槽位逐个 Unicode code point 检查。
  2. 丢弃不符合当前槽位的字符。
  3. 超过 mask 容量的字符会被截断。
  4. 重新生成 displayValuecomplete

程序直接写入 edit.value 或调用 reset() 不会触发 onChange

const code = new RenderMaskedTextEdit({  mask: 'AA-0000',  value: 'ab12x34',}) code.value        // 'ab1234'code.displayValue // 'ab-1234'

固定字符按输入进度显示,不会为尚未填写的槽位绘制 prompt character。例如 mask 为 000-000 时:

raw value display value
'' ''
'1' '1'
'123' '123-'
'1234' '123-4'

内置 mask token

Token 是否必填 接受字符
0 数字。
9 数字。
L Unicode 字母,包括中文等 \p{L} 字符。
? Unicode 字母。
A Unicode 字母或数字。
a Unicode 字母或数字。

其他字符按固定文本处理:

const dateLikeCode = new RenderMaskedTextEdit({  mask: '0000-00-00',})

这里的两个 - 由组件自动插入,不属于 raw value。

转义 token

反斜杠 \ 会把下一个字符转成固定文本。因为 TypeScript 字符串本身也使用反斜杠转义,代码中通常需要写成 \\

const prefixedCode = new RenderMaskedTextEdit({  // 界面格式:A-BF;第一个 A 是固定字符,两个 X 是自定义槽位。  mask: '\\A-XX',  definitions: {    X: {      pattern: /[A-F]/i,      transform: character => character.toUpperCase(),    },  },  value: 'bf',})

如果希望数字 0、字母 A 等内置 token 作为固定字符显示,也必须转义。

自定义 token

definitions 会与内置 token 合并;相同 key 会覆盖内置定义。

interface MaskTokenDefinition {  readonly pattern: RegExp  readonly required?: boolean  readonly transform?: (character: string) => string} type MaskTokenDefinitions =  Readonly<Record<string, MaskTokenDefinition>>

示例:

const upperHexDefinitions: MaskTokenDefinitions = {  X: {    pattern: /[0-9a-f]/i,    required: true,    transform: character => character.toUpperCase(),  },} const colorCode = new RenderMaskedTextEdit({  mask: '\\#XXXXXX',  definitions: upperHexDefinitions,  value: '12abef',}) colorCode.value        // '12ABEF'colorCode.displayValue // '#12ABEF'

自定义定义的约束:

  • pattern 应检查单个 Unicode code point。
  • required 省略时按 true 处理。
  • transform 必须返回一个 Unicode code point。
  • 转换后的字符仍必须通过 pattern,否则会被丢弃。
  • 可选 token 是顺序槽位,不能跳过中间可选槽位后继续填写后面的必填槽位。因此可选 token 优先放在 mask 尾部。

构造参数

参数 类型 默认值 说明
mask string 必填 固定格式。必须非空,并至少包含一个内置或自定义 token。
value string '' 初始 raw value。
definitions MaskTokenDefinitions 内置定义 新增或覆盖 token 定义。
placeholder string '' 空值提示。不是 mask prompt character。
readonly boolean false 可聚焦和选择,但不能修改、粘贴或清除。
disabled boolean false 不可聚焦和编辑。
status FormFieldStatus 'default' 字段状态色。
helperText string '' 字段下方的帮助或错误文字。
prefixText string '' mask 显示区域前的装饰文本,不属于 raw/display value。
suffixText string '' mask 显示区域后的装饰文本,不属于 raw/display value。
clearable boolean false 非空、非只读、非禁用时显示清除按钮。
fieldHeight number 主题默认高度 输入主体高度,不包含 helperText
onChange (value: string, details: MaskValue) => void undefined 用户输入、粘贴、删除或清除完成一次规范化后触发。
onSubmit (value: string, details: MaskValue) => void undefined 按 Enter 时触发。
onBlur (value: string, details: MaskValue) => void undefined 输入框失去焦点时触发。

构造 MaskEngine 时,空 mask 或不包含任何 token 的 mask 会直接抛出错误,避免生成一个看似可编辑、实际上没有输入槽位的字段。

MaskValue

interface MaskValue {  readonly raw: string  readonly display: string  readonly complete: boolean  readonly rawToDisplay: readonly number[]  readonly displayToRaw: readonly number[]}
字段 说明
raw 已接受的 raw value。
display 当前格式化文本。
complete 最后一个必填槽位是否已经填写。可选尾部槽位为空时仍可为 true
rawToDisplay raw 光标边界到 display 光标边界的映射,索引和值都使用 JavaScript 的 UTF-16 code unit 偏移。长度为 raw.length + 1
displayToRaw display 光标边界到 raw 光标边界的映射,索引和值都使用 JavaScript 的 UTF-16 code unit 偏移。长度为 display.length + 1

普通表单通常只使用 rawdisplaycomplete。两个位置映射主要供自定义编辑宿主、诊断和精确恢复选区使用。编辑器按完整 code point 占用一个 mask 槽位;如果浏览器给出的选区落在代理对内部,替换和删除会安全地归到该槽位边界。

这里承诺的是 Unicode code point,而不是用户感知的 grapheme cluster。由多个 code point 组成的 emoji、变音组合或复杂文字簇会占用多个槽位;需要按字素簇编辑时,应使用专门的文本编辑组件。

属性和方法

API 类型 说明
value string 当前 raw value。可读写;写入时重新规范化,但不触发回调。
displayValue string 当前格式化显示值,只读。
complete boolean 当前是否已填写全部必填槽位,只读。
engine MaskEngine 当前组件使用的 mask 引擎,只读。mask 在组件构造后不可替换。
textBox RenderTextBox 内部文本输入对象,供诊断和高级宿主使用。普通业务不应直接改它的 value
onChange 回调或 undefined 可在运行时替换。
onSubmit 回调或 undefined 可在运行时替换。
onBlur 回调或 undefined 可在运行时替换。
placeholder string 提示文字。
readonly boolean 只读状态。
disabled boolean 禁用状态。
status FormFieldStatus 字段状态。
helperText string 帮助或错误文字。
clearable boolean 是否允许清除。
isFocused boolean 当前是否拥有输入焦点,只读。
reset(value = '') void 使用新的 raw value 重置字段和选区,不触发回调。
focusIn() void 进入输入焦点。通常由焦点系统调用。
focusOut() void 结束输入并触发 onBlur。通常由焦点系统调用。

不要直接写 edit.textBox.value。这会绕过 raw/display 同步;业务应写 edit.value 或调用 reset()

MaskEngine

MaskEngine 是无界面的纯值工具,可用于 DataGrid 编辑适配、批量格式化和单元测试:

const engine = new MaskEngine('000-000') engine.formatRaw('1234').display// '123-4' engine.normalize('123-456').raw// '123456'
API 说明
mask 原始 mask 字符串。
definitions 合并后的 token 定义。
capacity 可编辑槽位总数。
formatRaw(raw) 按 raw value 生成 MaskValue
normalize(value) 规范化可能包含 mask 固定字符的显示文本,生成 MaskValue。纯 raw value 应使用 formatRaw()
normalizeDisplay(display, start?, end?) 规范化显示文本,并返回修正后的选区。
replace(display, start, end, text) 按 mask 槽位替换显示选区。
delete(display, start, end, direction) 删除选区、前一个槽位或后一个槽位。

normalizeDisplayreplacedelete 返回 MaskEditResult,它在 MaskValue 基础上增加 selectionStartselectionEnd

键盘、粘贴和 IME

操作 行为
普通输入 只保留符合当前槽位的字符,并自动插入固定字符。
Backspace 删除选区;没有选区时删除前一个值槽位,不会卡在分隔符上。
Delete 删除选区;没有选区时删除后一个值槽位。
粘贴 替换当前选区,过滤无效字符,重新计算 display value 和光标。
Enter 触发 onSubmit,随后按基础 TextBox 行为退出焦点。
Escape 退出焦点。
方向键、全选、复制、剪切 复用 TextBox 的选区和共享输入器行为。
Ctrl/Cmd + Z 撤销最近一次已生效的 mask 编辑;最多保留 100 个历史快照。
Ctrl/Cmd + Shift + ZCtrl + Y 重做最近一次撤销。
IME composition update 只显示输入法组合过程,不改 raw value。
IME composition end 按当前 token 规则接收或丢弃最终字符;整个 composition 作为一次历史事务。只有 raw/display 实际变化时才触发 onChange

L?Aa 使用 Unicode 字母规则,所以可以接受中文。数字 token 会在 IME 确认后拒绝中文输入。

回调时机

  • onChange 的第一参数始终是 raw value。
  • details 是同一时刻的完整 MaskValue
  • 固定字符插入、无效字符过滤和选区修正都在回调之前完成。
  • 只有规范化后的值实际变化时才触发 onChange;被 mask 完全拒绝的输入不会产生不变值通知。
  • 程序写入 value 和调用 reset() 不触发 onChange,同时会清空当前撤销/重做历史,避免撤销回到已经失效的外部状态。
  • onSubmitonBlur 会先根据当前显示文本刷新 raw/display,再执行回调。

只读和禁用

状态 可聚焦 可选择/复制 可编辑 可清除
正常 取决于 clearable
readonly
disabled

当前边界

  • mask 是构造期配置,组件不提供运行时替换 mask 的 setter。mask 变化时应重建组件。
  • 不显示未填写槽位的下划线或 prompt character。
  • 不内置正负数、小数、千分位、日期合法性或时间范围校验;这些应由对应的专业输入组件处理。
  • 可选槽位采用顺序填充,推荐只把可选 token 放在末尾。
  • complete 只表示必填槽位已填满,不代表业务值一定有效。例如 2026-99-99 可以填满日期形状,但仍需业务日期校验。
  • 当前没有作为 DataGrid 内置列编辑类型;需要表格内使用时,应由后续明确的 Grid editor contract 接入。

相关组件