ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Quasar 框架 QInput 组件完全指南:从基础用法到 Mask 掩码与表单验证的实战解析

2026/9/20 12:39:06 拓冰建站 浏览量
Quasar 框架 QInput 组件完全指南:从基础用法到 Mask 掩码与表单验证的实战解析 前端UI组件跨平台【免费下载链接】quasarQuasar Framework - Build high-performance VueJS user interfaces in record time项目地址https://gitcode.com/gh_mirrors/qu/quasar点击查看免费下载导读本文基于 Quasar Framework 官方文档docs/src/pages/vue-components/input.md编写系统讲解 UI 组件库中 QInput 的完整使用方式从五种互斥的设计风格filled/outlined/standout/borderless、文本输入与原生属性透传到业界少见的强大 Mask 掩码系统含自定义 token、反向填充、多掩码动态切换再到内部/外部/异步表单验证、无障碍支持与原生表单提交。读完本文你将掌握 QInput 在真实业务表单电话号码、金额、序列号、身份证等格式受限输入中的完整落地方案并能结合源码理解其底层行为。快速了解 QInputQInput 是 Quasar 框架中用于捕获用户文本输入的核心表单组件位于ui/src/components/input/QInput.js。它与原生input类似使用v-model双向绑定同时内置了错误与验证支持并提供丰富的样式、颜色与类型组合。从源码看QInput 的modelValue类型为String、Number或FileListSSR/SSG 下不含 FileList见 QInput.js意味着它天然覆盖了普通文本、数字和文件选择三种场景。组件基于 QField 构建QInput.js通过useField见ui/src/composables/private.use-field/use-field.js复用了 QField 的框架、标签、错误提示、插槽等全部能力因此 QInput 的所有属性与行为都可以视为QField 框架 原生 input/textarea 掩码/防抖等增强的组合。组件暴露的方法见 QInput.json方法说明focus()聚焦底层原生 input 元素blur()让底层原生 input 失去焦点select()选中输入框文本getNativeElement()获取原生 input/textarea DOM 元素已废弃请改用nativeElnativeEl是响应式计算属性computed同样返回底层原生元素。组件 API 的完整类型定义可查看 types/api/QInput.d.ts 或直接阅读QInput.json。设计DesignQInput 支持五种主要视觉设计。需要注意的是这五种设计彼此互斥一个 QInput 只能使用其中一种不能混用。Standard标准默认设计输入框底部有一条下划线。Filled填充输入框带有填充背景色。Outlined描边输入框四周有边框轮廓。Standout突出背景在聚焦/悬停时变化常用于 QToolbar 中集成搜索框等场景见 StandoutToolbar.vue。Borderless无边框不绘制边框、不改变背景色用于将输入框无缝嵌入其他组件中。颜色ColoringQInput 支持通过color属性改变主题色同时 Quasar 的dark布尔属性可强制切换暗色模式见 Dark.vue。颜色主题遵循 Quasar 全局色彩体系primary、secondary、accent 等可参考 ui/src/css/index.sass 中的主题变量定义。Rounded 与 Squarerounded属性仅在Filled、Outlined、Standout三种设计下生效用于将输入框四角变圆见 Rounded.vue。square属性同样只在上述三种设计下有意义用于去掉圆角、强制直角边框见 SquareBorders.vue。Force dark mode通过dark属性可以强制 QInput 使用暗色样式而不管当前应用是否处于暗色主题适用于局部区域深色化场景。基础功能原生属性透传QInput 上所有不在其 props 列表中的属性都会被自动透传给内部的原生元素input或textarea例如autocomplete、placeholder等。这是通过inheritAttrs: false加手动合并 attrs 实现的见 QInput.js透传时还会自动带上tabindex、maxlength、disabled、readonly等映射属性。这意味着你可以直接使用 HTML 原生规范中的属性无需额外封装。原生属性完整清单可参考 MDN 的 input 与 textarea 文档。Clearable 一键清空添加clearable属性后当有输入内容时会在输入框尾部出现一个清空图标点击后将 model 重置为null。从源码看清空动作调用onClear()QInput.js它会取消所有待执行的防抖/惰性更新并删除临时值然后通过 QField 的onClear机制重置显示。输入类型typetype属性支持渲染原生等价输入类型取值包括text、password、textarea、email、search、tel、file、number、url、time、date、datetime-local见 QInput.json。[!WARNING] 各浏览器对输入类型的支持与行为完全取决于浏览器自身渲染与 Quasar 核心代码无关。[!TIP] 某些输入类型如date、time始终会渲染浏览器控件。如果同时使用label建议配合stack-label让标签始终悬浮在上方否则标签会与原生控件重叠。数字类型使用数字输入时应同时使用v-model.number注意.number修饰符与typenumberq-input v-model.numberage typenumber labelAge /源码中对number类型做了专门处理输入过程中先暂存字符串形式的临时值temp.value在update:modelValue发出时 Vue 的.number修饰符会将其转换为数字同时floatingLabel计算属性对number类型会检查Number.isFinite避免空值/非法值时标签异常悬浮QInput.js。文件类型[!TIP] 需要文件选择时通常更推荐使用 QFile 或 QUploader 组件而非 QInput 的typefile。[!WARNING]切勿对typefile的 QInput 使用v-model浏览器安全策略不允许为文件输入设置 value。因此你只能读取它通过update:model-value事件无法写入。源码中对此有专门分支当type file时onInput直接 emite.target.filesFileList而非字符串值QInput.js且渲染时使用useFileFormDomProps提供 DOM 属性而非 valueQInput.js。Textarea 文本域将type设为textarea或使用autogrow即可渲染为多行文本域。文本域的行距随字体大小变化因此通过input-class/input-style调整字号时行距会自动保持均匀。当内容增长时可使用autogrow属性让文本域随内容自动增高。底层实现有两种路径见 use-autogrow.jsCSS 路径浏览器支持field-sizing: content时直接交给 CSS 处理性能最优JS 测量路径不支持时将 textarea 高度折叠为 1px、读取scrollHeight再写回为内联高度并用requestAnimationFrame合并每帧内的多次触发同时处理 Firefox 的 overflow 与滚动位置保留等边界情况。前缀与后缀Prefix and suffix通过prefix与suffix属性或对应的prepend/append插槽可在输入框前后附加静态文本适合单位如$、kg、货币符号等场景见 PrefixSuffix.vue。自定义标签Custom label使用label插槽可完全自定义标签的展示形式例如在标签内嵌入 QTooltipq-input label-slot filled template #label q-icon nameinfo size14px / 用户名 /template /q-input[!TIP] 使用label插槽时必须设置label-slot属性若需要在插槽元素上交互如 QTooltip 悬停请为元素添加all-pointer-eventsclass。Shadow text 阴影文本shadowText属性可以在输入内容之后显示一段影子文字用于预览提示完整格式例如输入金额时提示小数点后位数。源码中通过getShadowControl()渲染一个不可见副本加影子文字的叠加层QInput.js该功能对typefile不生效。Slots 中的 submit 按钮[!WARNING] 当把typesubmit的 QBtn 放入 QField / QInput / QSelect 的before、after、prepend或append插槽时必须在该 QBtn 上额外添加click监听器来调用表单提交方法。这些插槽内的 click 事件不会向上传播到父元素因此仅靠原生 form submit 无法触发。防抖Debounce当你在 watch model 时执行昂贵操作如请求远程校验希望用户先输入完成再触发更新而不是每次按键都更新 model。此时使用debounce属性单位毫秒q-input v-modelsearch debounce500 labelSearch /源码中防抖通过emitTimer setTimeout(emitValueFn, props.debounce)实现防抖期间把用户输入暂存在temp.value中以保持界面即时反馈定时器到点后才发出update:modelValueQInput.js。同时源码还处理了一个易被忽视的细节当 model 已被外部重置时会取消仍在途中的防抖发射cancelPendingValueEmission()避免过期中间值污染模型use-mask.js。惰性更新v-model.lazy使用v-model.lazy修饰符时model 只在用户完成编辑时更新原生change事件或输入框失焦时而不是每次按键都更新与原生input的行为一致。注意使用v-model.lazy时debounce属性会被忽略。源码中emitValueFn在 lazy 模式下保持待定状态直到onChangechange 事件或onFinishEditing失焦时被调用QInput.js。另外v-model.trim与v-model.number由 Vue 本身处理。加载状态Loading stateQInput 支持loading属性开启后显示加载指示器常用于异步校验或远程数据回填场景见 LoadingState.vue。Mask 掩码mask属性可以强制/辅助用户输入特定格式这是 QInput 最强大的功能之一实现位于 use-mask.js。[!WARNING] Mask 仅在type为text默认、search、url、tel或password时可用。源码通过getIsTypeText()检查类型并据此决定是否启用掩码逻辑use-mask.js。[!WARNING]与maxlength的冲突Mask 本身已按槽位限制输入长度因此不要与maxlength组合使用。原生maxlength统计的是完整显示值含字面符与填充字符任何小于掩码全长的值都会过早阻断输入而配合fill-mask时显示值始终是掩码全长这样的maxlength会直接锁死整个输入框。默认掩码 TokenToken说明#数字S字母 a-z大小写不敏感N字母数字字母大小写不敏感A字母自动转换为大写a字母自动转换为小写X字母数字字母自动转换为大写x字母数字字母自动转换为小写这些 token 在 use-mask.js 中定义A/a/X/x带有transform函数toLocaleUpperCase/toLocaleLowerCasepattern用于单字符匹配negate用于取反匹配。源码还针对纯 ASCII 的三种 pattern 做了零分配的性能优化patternTestersuse-mask.js其它 pattern 才回退到正则。除自定义字符串外mask还内置了命名掩码见 use-mask.js名称展开的掩码date####/##/##datetime####/##/## ##:##time##:##fulltime##:##:##phone(###) ### - ####card#### #### #### ####基本用法示例摘自 MaskBasic.vueq-input filled v-modelid labelSpecial ID mask###/## hintMask: ###/## / q-input filled v-modelphone labelPhone mask(###) ### - #### / q-input filled v-modelserialNumber labelSerial number maskAAAA - #### - #### - SSS /填充掩码fill-mask默认掩码在未填满时只显示已输入的部分。fill-mask属性布尔值或字符串会用指定字符传字符串时取第一个字符默认_填充掩码的剩余槽位q-input v-modeldate maskdate fill-mask0 labelDate /注意源码中一个关键边界处理当填充字符恰好满足某个 token如fill-mask0对#token仅凭渲染值无法区分填充与真实数据因此 use-mask 维护了innerValueDataLen填充前数据长度来精确判定每个位置是否承载真实数据避免每次按键都错误吞掉/多出一个填充字符use-mask.js。光标与按键行为Mask 会接管光标移动跨越掩码字面符以及BACKSPACE/DELETE的边界逻辑。你可以通过阻止其keydown事件来禁用掩码自身的按键处理——但注意这同时会取消浏览器对该键的原生处理例如keydown.left.prevent会让光标停留在原处而非跳过字面符重新定位光标需要自己实现。底层由onMaskedKeydown实现use-mask.js它维护了 Shift 多选锚点selectionAnchor与四种方向移动moveCursor.left/right/leftReverse/rightReverse。unmasked-value 原始值模式如果你希望强制用户按格式输入但 model 中保存的是去除格式的原始值则使用unmasked-value属性q-input v-modelphone maskphone unmasked-value labelPhone /此时 model 保存纯数字如0212345678显示层仍带格式。源码在updateMaskValue中对unmasked-value使用unmaskValue(preMasked)在填充之前去掩码use-mask.js。reverse-fill-mask 反向填充reverse-fill-mask强制用户从掩码末尾开始填充且允许输入长度不固定不足部分不占位q-input v-modelprice mask#.## fill-mask# reverse-fill-mask labelPrice /源码专门实现了maskValueReverse从右侧向左装配数据并处理了字面符在左侧数据落地前不提前输出等细节use-mask.js。多掩码动态切换当一个字段需要接受多种格式时例如电话号码可能是 8 位或 9 位本地号码可将mask绑定到计算属性根据值的长度选择掩码。两个关键细节保证可靠性使用unmasked-value让纯数字长度而非当前掩码字面符驱动切换决策给较短的掩码末尾多留一个 token 槽位使跨越阈值的那个数字能够被输入——一旦输入计算属性切换掩码并重新排版光标保持在原数据位置。实现示例可查看 MaskMultiple.vue。源码中掩码切换会保留光标前的数据字符数量dataBeforeCaret切换后在新的布局中重新锚定光标use-mask.js。自定义掩码 Tokenv2.18.4mask-tokens属性允许在默认 token 基础上新增自定义 token甚至可以覆盖部分/全部默认 token。自定义 token 的语法必须与默认 token 一致pattern必填匹配单个字符的正则字符串、negate必填不匹配的正则字符串、transform可选字符转换函数。示例摘自 MaskCustomTokens.vueq-input filled v-modelid labelSpecial ID maskAA-CC-XX-CC :mask-tokenscustomTokens /const customTokens { C: { pattern: [0-4a-eA-E], negate: [^0-4a-eA-E], transform: v v.toLocaleUpperCase() }, X: { pattern: [5-8], negate: [^5-8] } // 覆盖默认的 X }源码中mask-tokens通过getTokenMap解析并与默认 token map 合并{ ...DEFAULT_TOKEN_MAP, ...customTokens }且对mask-tokens做了深度监听变更时自动重算掩码use-mask.js。使用第三方掩码处理器你也可以轻松接入任意第三方掩码处理器。思路是利用 QField 的control插槽替换内部控件。以 v-money 指令为例从标准 QInputq-input filled v-modelprice labelPrice with 2 decimals mask#.## fill-mask# reverse-fill-mask hintMask: #.00 input-classtext-right /改为 QField 原生 input v-money 指令q-field filled v-modelprice labelPrice with v-money directive hintMask: $ #,###.00 # template #control{ id, floatingLabel, modelValue, emitValue } input :idid classq-field__input text-right :valuemodelValue changee emitValue(e.target.value) v-moneymoneyFormatForDirective v-showfloatingLabel / /template /q-fieldmoneyFormatForDirective: { decimal: ., thousands: ,, prefix: $ , suffix: #, precision: 2, masked: false /* doesnt work with directive */ }或使用 money 组件q-field filled v-modelprice labelPrice with v-money component hintMask: $ #,###.00 # template #control{ id, floatingLabel, modelValue, emitValue } money :idid classq-field__input text-right :model-valuemodelValue update:model-valueemitValue v-bindmoneyFormatForComponent v-showfloatingLabel / /template /q-fieldmoneyFormatForComponent: { decimal: ., thousands: ,, prefix: $ , suffix: #, precision: 2, masked: true }control插槽暴露的id用于 label 关联、floatingLabel标签是否悬浮、modelValue、emitValue是接入第三方控件的关键协议这正是 QField 将框架渲染与控件渲染解耦的体现。验证Validation内部验证:rules通过:rules属性验证 QInput传入内建规则数组或自定义校验器。自定义校验器是一个函数校验成功返回true失败返回错误消息字符串value condition || errorMessage // 示例 value value.includes(Hello) || Field must contain word Hello[!TIP] 出于性能考虑默认情况下规则的变化不会触发重新验证直到 model 变化。若希望规则变化时也触发验证使用reactive-rules布尔属性。代价是性能开销仅在确实需要时使用并且可以通过把规则写成计算属性而不是在模板中内联来略微缓解。调用 QInput 的resetValidation()方法可重置验证状态示例见 ValidationRequired.vueq-input refinputRef filled v-modelmodel labelRequired Field :rules[val !!val || Field is required] / q-btn labelReset Validation clickinputRef.resetValidation() /[!WARNING]原生约束与 rules 是两套体系原生 HTML 约束如email/url类型或透传到原生 input 的pattern/required属性只会在原生表单提交时由浏览器强制执行。程序化的validate()方法QInput 自身或外层 QForm只评估 rules不检查原生约束。因此任何需要被validate()捕获的约束都应同时写成规则例如:rules[email]。注意 QInput 提供内建的常用规则字符串如email、url等可直接复用。lazy-rules 触发时机设置lazy-rules后验证在字段失焦时触发readonly字段也触发只有disabled字段豁免错误显示期间每次变更都会重新验证一旦值合法错误立即清除。字段内部打开的菜单或对话框如append插槽中的 QPopupProxy在其打开期间保持字段聚焦不算失焦。若lazy-rules设置为字符串ondemand则验证仅在手动调用组件validate()方法或外层 QForm 提交时触发适合完全由表单控制的场景。异步规则Async rules规则支持异步使用 async/await 或直接返回 Promise。如果异步验证进行中值发生变化或字段失焦字段会在异步验证结束后自动重新验证确保显示的结论始终匹配当前值。[!TIP] 建议将异步规则与debounce属性配合使用避免每次按键都立即触发异步规则造成性能损耗。示例模式const rules [ async val { const ok await checkUnique(val) return ok || 该值已被占用 } ]外部验证External validation也可以完全使用外部验证只传入error和error-message属性需启用bottom-slots来显示错误消息q-input filled v-modelmodel :errorhasError error-message用户名已存在 bottom-slots /[!TIP] 根据需求你可以连接 Regle官方推荐方案或其他验证库到 QInput。错误消息的显示槽位也可以自定义见 ValidationSlots.vue例如在错误文本旁加图标或改变布局。无障碍Accessibilityv2.25QInput 在 QField 框架内渲染原生input或textarea因此 QField 的无障碍章节所述内容全部适用通过生成的 SSR 安全 id 建立 label 关联错误消息以rolealert播报并通过aria-invalid/aria-errormessage/aria-describedby从控件引用清空按钮可通过键盘操作。在此基础上label属性会额外作为aria-label暴露到原生元素自行设置的aria-label/aria-labelledby优先级更高disable与readonly会映射为原生disabled与readonly属性因此 readonly 输入框保留在 Tab 顺序中聚焦时显示聚焦态。其余原生属性placeholder、autocomplete、inputmode等均透传到原生元素。这与 QInput.js 中inputAttrs的组装逻辑完全一致。原生表单提交当 QInput 用于带action与method的原生表单时例如 Quasar 配合 ASP.NET 控制器必须指定name属性否则 formData 中不会包含该字段如果需要提交它的话form action/submit methodpost q-input nameusername v-modelusername labelUsername / /form源码通过useFormInputNameAttr为控件提供 name 属性QInput.js未设置name时该字段不会进入 formData。进阶结合源码理解输入管线了解 QInput 的底层工作流有助于排查疑难问题。核心输入管线如下输入事件用户键入触发onInput非 file 类型时读取e.target.value暂存与发射emitValue(val)根据修饰符决定发射策略——debounce走定时器、v-model.lazy挂起等待 change/blur、其余立即发射QInput.js掩码介入有 mask 时走updateMaskValue完成去掩码、重装配、光标定位与unmasked-value转换IME 输入法合成通过qComposing标记跳过掩码重写避免中文等输入法合成期间值被篡改QInput.js失焦收尾onFinishEditing清空暂存值、取消待发射的防抖定时器并同步显示值。对应的测试覆盖可参考 QInput.test.js 与 use-mask.test.js其中包含大量针对光标移动、填充字符边界、反向填充、防抖竞态等场景的回归用例。结语QInput 远不止是一个带样式的 input它由 QField 框架提供一致的布局/标签/错误体系自带防抖、惰性更新、加载态与无障碍支持更内置了一套可自定义 token、可反向填充、可动态切换的生产级掩码引擎。无论是简单的登录表单还是复杂的电话号码、金额、序列号输入QInput 都能在保持原生输入体验的同时完成格式约束与验证闭环。结合 input.md 官方文档、docs/src/examples/QInput 目录下的 37 个可运行示例以及 use-mask.js 等源码你可以进一步验证并扩展本文涉及的所有能力。赞分享前端UI组件跨平台【免费下载链接】quasarQuasar Framework - Build high-performance VueJS user interfaces in record time项目地址https://gitcode.com/gh_mirrors/qu/quasar点击查看免费下载相关推荐Quasar QDate 组件完全指南从基础用法到波斯日历、无障碍与表单集成的实战手册Quasar QDate 组件完全指南从基础用法到波斯日历、无障碍与表单集成的实战手册 导读 本文以 Quasar Framework 官方文档 QDate前端UI组件跨平台react-native-elements Input 组件完全指南从基础用法到表单交互实战react native elements Input 组件完全指南从基础用法到表单交互实战 导读 本文围绕 react native elements 的UI组件移动开发前端ElementVue 2.0Radio 单选框组件完全指南从基础用法到源码实现ElementVue 2.0Radio 单选框组件完全指南从基础用法到源码实现 Element 的 Radio 组件族 el radio 、 el ra前端UI组件设计系统创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考