PrimeVue Password 组件实战指南:密码强度检测、遮罩切换与表单集成
PrimeVue Password 组件实战指南:密码强度检测、遮罩切换与表单集成
密码输入是表单中最常见的场景之一,而 PrimeVue 的 Password 组件在标准密码框的基础上,内置了实时强度指示器(Strength Meter)、明文切换(Toggle Mask)、一键清空(Clear Icon)等能力,并原生支持无障碍标注与 PrimeVue Forms 校验体系。本篇指南以仓库中的官方组件文档 password.md 为骨架,结合 Password.vue 等源码实现,系统讲解该组件的全部用法、核心属性、底层原理与主题定制方式,读完即可在真实项目中直接落地使用。
组件定位与引入方式
Password 是一个"带强度指示的密码输入组件":它在内部封装了 InputText,并在输入框聚焦或敲击键盘时弹出覆盖层展示密码强度。官方对它的定义是一句话——"Password displays strength indicator for password fields"(为密码字段显示强度指示器)。
引入组件时,从 primevue/password 子路径按需导入:
import Password from 'primevue/password';
在应用级注册后,模板中即可直接使用 <Password />。组件源码位于 packages/primevue/src/password/,由三个核心文件构成:
- Password.vue:组件主实现,包含模板、状态与方法;
- BasePassword.vue:基于
BaseInput定义全部 Props 的默认值; - Password.d.ts:完整的 TypeScript 类型声明(Props、Slots、Emits、PassThrough 选项)。
基础用法:v-model 双向绑定
Password 通过 v-model 实现值的双向绑定,这与 InputText 保持一致:
<Password v-model="value" :feedback="false" />
其中 feedback 默认值为 true(见 BasePassword.vue),控制是否显示强度指示器。当你的场景只需要一个普通密码框(例如登录页只做提交校验、不需要强度提示)时,显式传入 :feedback="false" 可以去掉弹出层,让组件退化为纯粹的密码输入框。
完整的 Composition API 写法如下:
<template>
<div class="card flex justify-center">
<Password v-model="value" :feedback="false" />
</div>
</template>
<script setup>
import { ref } from 'vue';
const value = ref(null);
</script>
从源码角度看,值的变化链路是:输入事件触发 onInput → writeValue(event.target.value, event) 写入模型 → $emit('update:modelValue', ...),测试用例 Password.spec.js 验证了 update:modelValue 事件会携带输入值发出。
状态与外观:禁用、填充、校验态与尺寸
Disabled(禁用)
传入 disabled 后,输入框不可编辑、不可聚焦,同时禁用态样式由主题自动处理:
<Password disabled placeholder="Disabled" />
Filled(填充样式)
variant 属性用于切换输入框的外观风格。默认值为 null(outlined 描边风格),指定为 "filled" 时使用填充背景,获得比默认描边更强的视觉强调:
<Password v-model="value" :feedback="false" variant="filled" />
Invalid(校验失败态)
invalid 用于标记校验失败的输入状态,典型用法是与表单校验库联动:当值为空时置为无效。示例中同时演示了描边与填充两种变体下的无效样式:
<Password v-model="value1" :invalid="!value1" placeholder="Password" />
<Password v-model="value2" :invalid="!value2" variant="filled" placeholder="Password" />
invalid 默认值为 false(BasePassword.vue),该 prop 会直接透传给内部 InputText,从而应用红色边框等无效态样式。
Sizes(尺寸)
除了基础尺寸,Password 还提供 small 与 large 两种替代尺寸:
<div class="card flex flex-col items-center gap-4">
<Password v-model="value1" size="small" placeholder="Small" />
<Password v-model="value2" placeholder="Normal" />
<Password v-model="value3" size="large" placeholder="Large" />
</div>
Fluid(撑满容器)
fluid 为 true 时组件占据容器 100% 宽度:
<Password v-model="value" :feedback="false" fluid />
该 prop 同样会透传给内部 InputText,并与 $fluid 注入($pcFluid)协同工作,使得组件也可以放在全局 Fluid 容器中自动获得流体宽度。
图标交互:一键清空与明文切换
Clear Icon(清空图标)
启用 showClear 后,输入框右侧会出现清空图标,点击即可重置值:
<Password v-model="value" :feedback="false" showClear inputClass="w-56" />
源码中 isClearIconVisible 的计算逻辑是 showClear && this.$filled && !this.disabled(Password.vue),即仅当有内容且未禁用时才显示图标;点击后调用 onClearClick 执行 writeValue(null, {}) 清空值(Password.vue)。inputClass 用于给内部输入框追加 Tailwind/自定义样式类。
ToggleMask(明文切换)
toggleMask 启用后,输入框旁会显示一个眼睛图标,点击可在密文与明文之间切换:
<Password v-model="value" toggleMask />
底层实现非常直观:unmasked 状态驱动 inputType 计算属性返回 'text' 或 'password'(Password.vue),onMaskToggle 负责翻转该状态(Password.vue)。切换前后的图标分别由 maskIcon(隐藏/恢复遮罩)与 unmaskIcon(显示明文)两个 prop 控制,两者均可传入自定义图标类名。
测试用例 Password.spec.js 验证了切换前后 p-password-mask-icon 与 p-password-unmask-icon 两个类名在 DOM 中的存在与消失,可作为理解该行为的参考。
标签组合:FloatLabel 与 IftaLabel
Password 支持与 PrimeVue 的两种标签组件组合使用。
FloatLabel(浮动标签)
浮动标签在聚焦时浮到输入框上方。示例演示了三种变体:默认的 over(标签悬浮于边框之上)、variant="in"(标签嵌入填充框内)以及 variant="on"(标签置于边框上):
<FloatLabel>
<Password v-model="value1" inputId="over_label" />
<label for="over_label">Over Label</label>
</FloatLabel>
<FloatLabel variant="in">
<Password v-model="value2" inputId="in_label" variant="filled" />
<label for="in_label">In Label</label>
</FloatLabel>
<FloatLabel variant="on">
<Password v-model="value3" inputId="on_label" />
<label for="on_label">On Label</label>
</FloatLabel>
组合时必须通过 inputId 与 <label> 的 for 属性一一对应,保证点击标签即可聚焦输入框。
IftaLabel(内联顶部标签)
IftaLabel 创建字段内部的顶部对齐标签,通常配合 variant="filled" 使用:
<IftaLabel>
<Password v-model="value" inputId="password" variant="filled" />
<label for="password">Password</label>
</IftaLabel>
强度指示器(Meter)与强度判定原理
默认情况下(feedback 为 true),输入过程中会弹出覆盖层,内部包含一个强度条(meter)与对应的强度文案:
<Password v-model="value" />
这是 Password 区别于普通 InputText 的核心能力。强度判定由两条正则驱动,其默认值定义在 BasePassword.vue:
mediumRegex(中等强度,默认):^(((?=.*[a-z])(?=.*[A-Z]))|((?=.*[a-z])(?=.*[0-9]))|((?=.*[A-Z])(?=.*[0-9])))(?=.{6,})—— 满足"小写+大写 / 小写+数字 / 大写+数字"任一组合且总长度 ≥ 6;strongRegex(高强度,默认):^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.{8,})—— 同时包含小写、大写、数字且总长度 ≥ 8。
两者均可通过同名 prop 传入自定义的 string | RegExp 覆盖。
判定逻辑在 Password.vue 的 testStrength 方法中:先测试强正则(命中即 level 3),再测试中等正则(命中即 level 2),否则只要有输入字符即为 level 1。随后 checkPasswordStrength 将等级映射为文案与宽度(Password.vue):
| 等级 | 文案来源 | 强度条宽度 |
|---|---|---|
| 1(弱) | weakText(默认取 locale.weak) |
33.33% |
| 2(中) | mediumText(默认取 locale.medium) |
66.66% |
| 3(强) | strongText(默认取 locale.strong) |
100% |
| 0(空) | promptText(默认取 locale.passwordPrompt) |
无 |
交互细节:聚焦时通过 setPasswordMeter 根据当前值初始化强度;keyup 时实时重算(onKeyUp);失焦或按 Escape 时关闭弹出层(Password.vue)。覆盖层默认挂载到 body(appendTo 默认值,可通过 "self" 或选择器/HTMLElement 修改),并实现了滚动关闭、窗口 resize 关闭、ZIndex 管理以及 OverlayEventBus 联动等标准 overlay 行为。
测试用例 Password.spec.js 验证了输入字符 P 后 meter 文案变为 Weak 且强度条获得 p-password-meter-weak 类名,与上述逻辑完全吻合。
多语言文案:Locale 与组件级覆盖
强度指示器相关的四段文案——提示、弱、中、强——默认全部取自 PrimeVue 的全局 locale 配置(源码中 weakText、mediumText、strongText、promptText 的 fallback 链,见 Password.vue)。若要为单个组件定制文案,直接传入四个 prop 即可:
<Password
v-model="value"
promptLabel="Choose a password"
weakLabel="Too simple"
mediumLabel="Average complexity"
strongLabel="Complex password"
/>
如需在整个应用中统一翻译所有 Password 组件的文案,应通过 PrimeVue 的全局 locale 配置进行设置,而不是逐组件传 prop。
表单集成:与 PrimeVue Forms 深度联动
Password 可无缝接入 PrimeVue Forms 体系。在 <Form> 内通过 name 属性注册字段,配合 zodResolver 定义校验规则,并通过 $form.password 读取校验状态与错误信息:
<Form v-slot="$form" :resolver="resolver" :initialValues="initialValues" @submit="onFormSubmit" class="flex flex-col gap-4 w-full sm:w-64">
<div class="flex flex-col gap-1">
<Password name="password" placeholder="Password" :feedback="false" fluid />
<template v-if="$form.password?.invalid">
<Message v-for="(error, index) of $form.password.errors" :key="index" severity="error" size="small" variant="simple">{{ error.message }}</Message>
</template>
</div>
<Button type="submit" severity="secondary" label="Submit" />
</Form>
脚本部分使用 Zod 描述密码规则,示例覆盖了长度上下限以及小写、大写、数字三类字符约束:
<script setup>
import { ref } from 'vue';
import { zodResolver } from '@primevue/forms/resolvers/zod';
import { useToast } from "primevue/usetoast";
import { z } from 'zod';
const toast = useToast();
const initialValues = ref({
password: ''
});
const resolver = ref(zodResolver(
z.object({
password: z
.string()
.min(3, { message: 'Minimum 3 characters.' })
.max(8, { message: 'Maximum 8 characters.' })
.refine((value) => /[a-z]/.test(value), {
message: 'Must have a lowercase letter.'
})
.refine((value) => /[A-Z]/.test(value), {
message: 'Must have an uppercase letter.'
})
.refine((value) => /\d/.test(value), {
message: 'Must have a number.'
})
})
));
const onFormSubmit = ({ valid }) => {
if (valid) {
toast.add({ severity: 'success', summary: 'Form is submitted.', life: 3000 });
}
};
</script>
提交时 onFormSubmit 接收 { valid },仅在全部字段通过校验时执行提交逻辑。校验失败时,字段上的 invalid 状态会自动由 Forms 上下文驱动,无需手动维护 :invalid 绑定。
模板定制:header、content、footer 插槽
Password 的弹出覆盖层提供了 3 个插槽用于自定义:header(覆盖层顶部)、content(中部,注意传入该插槽会覆盖默认的强度条)、footer(底部)。示例用 header 展示标题、用 footer 展示密码规则清单:
<Password v-model="value">
<template #header>
<div class="font-semibold text-xm mb-4">Reset Password</div>
</template>
<template #footer>
<Divider />
<ul class="pl-2 my-0 leading-normal text-sm">
<li>At least one lowercase</li>
<li>At least one uppercase</li>
<li>At least one numeric</li>
<li>Minimum 8 characters</li>
</ul>
</template>
</Password>
此外,图标区域还支持更细粒度的插槽(见 Password.d.ts):maskicon / unmaskicon(明文切换图标,分别携带 toggleCallback 作用域)、clearicon(清空图标,携带 clearCallback),以及自 v4.0 起已弃用的 hideicon / showicon 旧名称。
Props 全解:默认值、正则与覆盖层定位
Password 的专有 Props(含默认值,均取自 BasePassword.vue)如下:
| Name | Type | Default | Description |
|---|---|---|---|
| modelValue | Nullable<string> | - | 组件值(受控) |
| defaultValue | Nullable<string> | - | 非受控模式下的默认输入值 |
| name | string | - | 表单提交用的 name 属性 |
| promptLabel | string | - | 提示输入密码的文案,默认取 locale |
| mediumRegex | string | RegExp | ^(((?=.*[a-z])(?=.*[A-Z]))|((?=.*[a-z])(?=.*[0-9]))|((?=.*[A-Z])(?=.*[0-9])))(?=.{6,}) |
中等强度判定正则 |
| strongRegex | string | RegExp | ^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.{8,}) |
高强度判定正则 |
| weakLabel | string | - | 弱密码文案,默认取 locale |
| mediumLabel | string | - | 中等密码文案,默认取 locale |
| strongLabel | string | - | 强密码文案,默认取 locale |
| feedback | boolean | true | 是否显示强度指示器 |
| appendTo | HTMLElement | "body" | "self" | body | 覆盖层挂载位置(选择器或元素) |
| toggleMask | boolean | false | 是否显示明文切换图标 |
| maskIcon | string | - | 隐藏明文(恢复遮罩)的图标类 |
| unmaskIcon | string | - | 显示明文的图标类 |
| showClear | boolean | false | 是否显示清空图标 |
| size | "small" | "large" | - | 组件尺寸 |
| invalid | boolean | false | 无效态样式 |
| disabled | boolean | false | 禁用态 |
| variant | "outlined" | "filled" | null | 输入框外观变体 |
| placeholder | string | - | 占位文本 |
| required | boolean | false | 提交表单前必填 |
| fluid | boolean | null | 是否撑满容器宽度 |
| autofocus | boolean | null | 页面加载时自动聚焦 |
| inputId | string | - | 内部 input 元素的 id |
| inputStyle | object | - | 输入框内联样式 |
| inputClass | string | object | - | 输入框样式类 |
| inputProps | InputHTMLAttributes | - | 透传给内部 input 的全部 HTML 属性 |
| panelId | string | - | 覆盖层面板元素 id |
| panelClass | string | object | - | 覆盖层面板样式类 |
| panelStyle | object | - | 覆盖层面板内联样式 |
| panelProps | HTMLAttributes | - | 透传给覆盖层面板 div 的属性 |
| overlayId | string | - | overlay 元素 id |
| overlayClass | string | object | - | overlay 样式类 |
| overlayStyle | object | - | overlay 内联样式 |
| overlayProps | HTMLAttributes | - | 透传给 overlay div 的属性 |
| ariaLabelledby | string | - | 建立与标签元素的关联 |
| ariaLabel | string | - | 无障碍标签文本 |
| formControl | Record<string, any> | - | 表单控制对象(校验/表单状态) |
| dt | any | - | 通过 design tokens 生成 scoped CSS 变量 |
| pt | PassThrough<PasswordPassThroughOptions> | - | 向内部 DOM 元素传递属性 |
| ptOptions | any | - | 配置 passthrough(pt) 选项 |
| unstyled | boolean | false | 移除组件核心样式 |
需要说明的是,Password 继承了大量标准 HTML/ARIA 属性并透传给底层 input 元素(如 autocomplete、maxlength、pattern、readonly、tabindex 以及全套 aria-* 属性、on* 事件监听器等),这些与原生 <input type="password"> 的行为一致,通常无需在组件层额外处理。完整的属性声明可查阅 Password.d.ts。
Pass Through 深度定制
如果不满足于默认 DOM 结构,可以通过 pt 逐层定制内部元素。Password 支持的 PassThrough 选项(对应 Password.d.ts):
| Name | Description |
|---|---|
| root | 根元素 |
| pcInputText | 内部 InputText 组件 |
| maskIcon | 遮罩图标元素 |
| unmaskIcon | 取消遮罩图标元素 |
| clearIcon | 清空图标元素 |
| overlay | overlay 元素 |
| content | overlay 内容元素 |
| meter | 强度条元素 |
| meterLabel | 强度条标签(进度)元素 |
| meterText | 强度条文案元素 |
| hiddenAccesible | 隐藏的无障碍(aria-live)元素 |
| hooks | 生命周期钩子管理 |
| transition | Vue Transition API 控制 |
配合 unstyled(移除组件自带样式)与全局主题体系,可以完全掌控 Password 的渲染结果与样式。官方完整的 PassThrough 示例可参考 apps/showcase/doc/password/pt/。
主题定制:CSS 类与设计令牌
CSS Classes
Password 暴露的样式类由 PasswordStyle.js 定义,与文档一致:
| Class | Description |
|---|---|
| p-password | 根元素类名 |
| p-password-input | pt 输入元素类名 |
| p-password-mask-icon | 遮罩图标类名 |
| p-password-unmask-icon | 取消遮罩图标类名 |
| p-password-clear-icon | 清空图标类名 |
| p-password-overlay | overlay 元素类名 |
| p-password-meter | 强度条元素类名 |
| p-password-meter-label | 强度条进度元素类名 |
| p-password-meter-text | 强度条文案元素类名 |
其中根元素还会根据状态追加 p-inputwrapper-filled(有值)、p-inputwrapper-focus(聚焦)、p-password-fluid(流体宽度)等修饰类;强度条进度元素会按强度追加 p-password-meter-weak / p-password-meter-medium / p-password-meter-strong。
Design Tokens
主题层面的外观统一由设计令牌驱动,Password 相关令牌及其 CSS 变量如下:
| Token | CSS Variable | Description |
|---|---|---|
| password.meter.background | --p-password-meter-background | 强度条背景 |
| password.meter.border.radius | --p-password-meter-border-radius | 强度条圆角 |
| password.meter.height | --p-password-meter-height | 强度条高度 |
| password.icon.color | --p-password-icon-color | 图标颜色 |
| password.overlay.background | --p-password-overlay-background | overlay 背景 |
| password.overlay.border.color | --p-password-overlay-border-color | overlay 边框色 |
| password.overlay.border.radius | --p-password-overlay-border-radius | overlay 圆角 |
| password.overlay.color | --p-password-overlay-color | overlay 文字颜色 |
| password.overlay.padding | --p-password-overlay-padding | overlay 内边距 |
| password.overlay.shadow | --p-password-overlay-shadow | overlay 阴影 |
| password.content.gap | --p-password-content-gap | 内容间距 |
| password.strength.weak.background | --p-password-strength-weak-background | 弱强度背景 |
| password.strength.medium.background | --p-password-strength-medium-background | 中强度背景 |
| password.strength.strong.background | --p-password-strength-strong-background | 强强度背景 |
在仓库的 packages/themes/src/presets/ 下,Aura、Lara、Material、Nora 四套预设主题均包含独立的 password 令牌定义(如 Aura 主题入口),可作为自定义主题时的参考起点。Showcase 中关于主题定制的更完整演示位于 apps/showcase/doc/password/theming/。
小结
PrimeVue Password 组件在密码输入框之上叠加了三层能力:强度反馈(feedback + 可自定义的正则与文案)、交互辅助(toggleMask 明文切换、showClear 一键清空)、生态集成(FloatLabel/IftaLabel 标签组合、PrimeVue Forms 校验、PassThrough 与设计令牌主题定制)。理解其"InputText + 弹出覆盖层"的架构以及 testStrength 的等级判定逻辑,就能在各类注册、重置密码与表单校验场景中灵活配置,必要时还可通过自定义正则、插槽与设计令牌将其改造成符合业务规范的安全输入组件。