--- title: Input 输入框 description: 单行 / 密码 / 数字 / 多行四种模式,支持清除、前后缀与字数统计 --- # Input 输入框 `Input` 是受控输入控件:值通过 `v-model` 双向绑定,`type` 决定它是单行、密码、数字还是多行文本。 ## 何时使用 - 录入短文本(名称、标题、编码)用默认模式; - 密码输入用 `type="password"`(自带显示/隐藏切换); - 只允许数字的字段用 `type="number"`(限制字符并转换类型); - 描述、备注等多行文本用 `type="textarea"`; - 需要从固定选项里选值,请用 [Select](/ui/form/select)。 ## 基础用法 `v-model` 的值类型是 `string`;`type="number"` 时提交值为 `number`(空值保留为 `''`)。 ## 密码输入 `type="password"` 会在右侧渲染一个显示/隐藏按钮,按钮带 `aria-pressed` 与无障碍标签。 密码框建议同时设置 `autocomplete="current-password"`,让浏览器密码管理器正确识别。 ## 数字输入 `type="number"` 做了三件事:过滤非数字字符、保留输入中间态(`12.` 不会被打断)、**失焦或回车时把字符串提交为 `Number`**。 ## 多行文本 `rows` 是初始行数;`show-count` 显示字数统计;右下角有拖拽手柄,可以拖拽或聚焦后用 `↑ / ↓ / Home` 调整高度(聚焦后是 `role="slider"`)。 ## 可清除 `clearable` 时,有值且 hover / 聚焦会出现清除按钮;点击清空值并触发 `clear` 事件。 ## 前后缀插槽 `#prefix` / `#suffix` 放图标或单位,图标尺寸跟随字号(`1em`)。 ## 校验状态 `status` 让输入框表达校验结果:`error` 红边、`warning` 黄边。配合 `G3FormItem` 时通常由表单自动管理,无需手写。 ## 实例方法 通过 `ref` 调用 `focus(options)` / `select()` / `blur()`,用于「点击单元格进入编辑」这类交互: ```ts const inputRef = ref | null>(null) inputRef.value?.focus({ cursor: 'all' }) // 聚焦并全选 inputRef.value?.focus({ preventScroll: true }) // 聚焦但不滚动页面 ``` ## API ### Props | 名称 | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | `modelValue` | `string \| number` | `''` | 双向绑定的值 | | `type` | `'default' \| 'password' \| 'number' \| 'textarea'` | `'default'` | 输入模式 | | `disabled` | `boolean` | `false` | 禁用态 | | `readonly` | `boolean` | `false` | 只读态:可聚焦、可复制,但不可修改 | | `status` | `'' \| 'error' \| 'warning'` | `''` | 校验状态 | | `clearable` | `boolean` | `false` | 有值时显示清除按钮(hover / 聚焦时出现),多行模式不支持 | | `allowClear` | `boolean` | — | **已废弃**,改用 `clearable`(与 Select / DatePicker 统一);保留仅为兼容旧代码 | | `showCount` | `boolean` | `false` | 显示字数统计(`maxlength` 存在时显示 `当前 / 上限`) | | `maxlength` | `string \| number` | — | 最大长度,透传给原生 `maxlength` | | `rows` | `string \| number` | `3` | 多行模式的初始行数(仅 `textarea` 生效) | | `placeholder` | `string` | — | 占位文案。声明为 prop 是为了让它落到内部 `` 而不是外层容器 | | `autocomplete` | `string` | — | 浏览器自动填充语义,如 `username` / `current-password` / `off` | ### Events | 名称 | 参数 | 说明 | | --- | --- | --- | | `update:modelValue` | `(value: string \| number)` | 输入时触发。`number` 模式提交 `number`,清空时为 `''` | | `change` | `(value: string \| number, event: Event)` | 原生 `change`(失焦或回车后值变化)。`number` 模式在此时完成类型转换 | | `focus` | `(event: FocusEvent)` | 获得焦点 | | `blur` | `(event: FocusEvent)` | 失去焦点 | | `clear` | `()` | 点击清除按钮(此时 `update:modelValue` 先发出 `''`) | ### Slots | 名称 | 参数 | 说明 | | --- | --- | --- | | `prefix` | — | 输入框左侧内容(图标、单位),多行模式不渲染 | | `suffix` | — | 输入框右侧内容,多行模式不渲染 | ### Exposed(通过 ref 调用) | 名称 | 签名 | 说明 | | --- | --- | --- | | `focus` | `(options?: { preventScroll?: boolean; cursor?: 'all' }) => void` | 聚焦;`cursor: 'all'` 聚焦后全选 | | `select` | `() => void` | 选中全部内容 | | `blur` | `() => void` | 失焦 | ### 类型定义 ```ts export type InputType = 'default' | 'password' | 'number' | 'textarea' export type InputStatus = '' | 'error' | 'warning' export interface InputProps { modelValue?: string | number type?: InputType disabled?: boolean readonly?: boolean status?: InputStatus clearable?: boolean allowClear?: boolean // 已废弃,改用 clearable showCount?: boolean maxlength?: string | number rows?: string | number placeholder?: string autocomplete?: string } export interface InputFocusOptions { preventScroll?: boolean cursor?: 'all' } ``` ### 样式变量 | 变量 | 默认值 | 说明 | | --- | --- | --- | | `--g3-control-height` | `32px` | 输入框高度(单行) | | `--g3-input-resize-handle` | 右下角手柄 | 多行模式的拖拽手柄位置由组件内部处理 | | `--g3-color-primary` / `--g3-color-primary-ring` | `#18181b` / 主色 20% | 聚焦边框与聚焦环 | | `--g3-color-danger` / `--g3-color-warning` | `#ec4246` / `#e79a0d` | `error` / `warning` 边框 | ## 实现说明 - **数字模式的取舍**:输入过程保留字符串(否则用户打不出 `12.`),只在 `change` / 失焦时转为 `Number`,空串保持 `''`,避免 `Number('')` 变成 `0`; - 光标位置在数字过滤后会重新计算(`setSelectionRange`),因此在中间插入非法字符不会把光标弹到末尾; - 多行模式的高度拖拽用 Pointer Events + `requestAnimationFrame` 合并更新,拖拽期间改的是内联 `height`(从小高度往大拖不会跳变); - `placeholder` 等原生属性声明为 prop 是刻意的:容器是 `
`,如果不声明,`placeholder` 会作为 fallthrough 属性挂到外层容器上,对真实输入框无效; - 聚焦样式用 `--g3-color-primary-ring` 画 2px 外环(而非 `outline`),这样在 `Space` / `Grid` 里不会因为 outline 被相邻元素裁掉。