密码可见性切换(眼睛图标动画 + 强度检测源码)
密码可见性切换源码:眼睛图标开关动画切换明文/密文,四格强度条随输入实时变色,长度与字符组合双维度评分,原生 JS 零依赖,注册表单安全体验必备。
效果演示(真实可交互)
密码输入框有两个高频微交互:一是「显示/隐藏密码」的眼睛开关,二是输入时的强度反馈。演示区是一个完整的密码设置卡片:点击右侧眼睛图标,睁开与闭合两枚图标交叉旋转切换,同时输入框在明文与密文间切换,焦点保持不丢失;下方四格强度条随输入实时变化——输入超过 8 位亮一格,超过 12 位再亮一格,大小写混用、数字与符号并用分别再加分,最多四格全亮。状态文字同步给出「弱 / 中 / 强 / 极强」的明确建议。整个过程无需提交表单,全部在 input 事件里即时计算。强度条四格对应四个评分维度,配色采用红橙蓝绿阶梯,色弱用户也能通过格子数量与文案区分。评分逻辑是纯函数,不依赖任何框架,可单独抽出来做单元测试,也方便对接团队自己的密码策略。强度检测的目的是引导而非阻拦:给出明确加分项(更长、更丰富)比单纯报错更能促成好密码;文案建议同时说明「怎么改」,而不是只给一个负面评价,用户体验更友好。
设置密码
请输入至少 8 位密码
点击右侧眼睛切换明文/密文,强度条随输入实时变化
完整代码
HTML:锁图标、输入框、眼睛按钮三层结构,眼睛按钮里放两枚 SVG 交叉切换:
<div class="pv-field">
<svg class="pv-lock"><!-- 锁图标 --></svg>
<input class="pv-input" id="pvInput" type="password" placeholder="输入密码" autocomplete="new-password">
<button class="pv-eye" id="pvEye" aria-label="显示密码" aria-pressed="false">
<svg class="pv-eye-open"><!-- 睁眼 --></svg>
<svg class="pv-eye-close"><!-- 闭眼 --></svg>
</button>
</div>
<div class="pv-meter" id="pvMeter"><span></span><span></span><span></span><span></span></div>
<p class="pv-status" id="pvStatus">请输入至少 8 位密码</p>
CSS:两枚眼睛图标重叠定位,用 opacity + 旋转做交叉切换:
.pv-eye svg { grid-area: 1 / 1; transition: opacity .25s ease, transform .3s cubic-bezier(.34,1.4,.64,1); }
.pv-eye-close { opacity: 0; transform: scale(.5) rotate(-90deg); }
.pv-eye.pv-on .pv-eye-open { opacity: 0; transform: scale(.5) rotate(90deg); }
.pv-eye.pv-on .pv-eye-close { opacity: 1; transform: scale(1) rotate(0); }
强度条:四格共用背景,按分数点亮前 N 格并换色:
.pv-meter { display: flex; gap: 6px; }
.pv-meter span { flex: 1; height: 5px; border-radius: 4px; background: #e8ecf7; transition: background .3s ease; }
.pv-meter.pv-s1 span:nth-child(-n+1) { background: #ef4444; } /* 弱:红 */
.pv-meter.pv-s2 span:nth-child(-n+2) { background: #f59e0b; } /* 中:橙 */
.pv-meter.pv-s3 span:nth-child(-n+3) { background: #3b82f6; } /* 强:蓝 */
.pv-meter.pv-s4 span { background: #22c55e; } /* 极强:绿 */
原生 JS:切换可见性 + 双维度强度评分:
const input = document.getElementById('pvInput');
const eye = document.getElementById('pvEye');
const meter = document.getElementById('pvMeter');
const status = document.getElementById('pvStatus');
eye.addEventListener('click', () => {
const show = input.type === 'password';
input.type = show ? 'text' : 'password';
eye.classList.toggle('pv-on', show);
eye.setAttribute('aria-pressed', String(show));
input.focus(); // 切换后焦点留在输入框,键盘用户可继续输入
});
function score(v) {
let s = 0;
if (v.length >= 8) s++; // 长度维度
if (v.length >= 12) s++;
if (/[a-z]/.test(v) && /[A-Z]/.test(v)) s++; // 大小写混用
if (/\d/.test(v) && /[^a-zA-Z0-9]/.test(v)) s++; // 数字 + 符号
return s;
}
input.addEventListener('input', () => {
const v = input.value;
const s = score(v);
meter.className = 'pv-meter' + (v ? ' pv-s' + Math.max(1, s) : '');
status.textContent = !v ? '请输入至少 8 位密码' : s === 1 ? '弱:太短或太单一' : /* 更多文案 */ '';
});
参数说明
| 参数 | 默认值 | 说明 |
|---|---|---|
| 密码长度门槛 | >= 8 / >= 12 | 两档加分,可按安全策略调整 |
| 组合加分 | 大小写混用 / 数字+符号 | 每满足一项 +1 分,满分 4 分 |
| 图标切换 | opacity + rotate + scale | 交叉旋转淡入淡出,scale(.5) 起点更有弹感 |
| 焦点保持 | input.focus() | 切换后不丢焦点,连续输入不断档 |
| 强度配色 | 红 / 橙 / 蓝 / 绿 | 与分数一一对应,色弱用户可配合文案理解 |
兼容性与性能
- 原生 JS 零依赖,正则评分在每次
input触发,计算量可忽略,长密码也毫无压力 - 图标切换与强度条换色均为 transform/opacity/background 动画,走合成器与重绘轻路径
- 眼睛按钮是真实
<button>,带aria-pressed状态与:focus-visible焦点环,键盘可操作 autocomplete="new-password"让浏览器密码管理器正常接管,不影响保存密码功能- 眼睛按钮在切换后主动把焦点还给输入框,键盘用户切换完可以立即继续打字;
aria-pressed状态全程同步,读屏朗读的开关语义与视觉一致
常见问题
Q: 切换明文后密码被旁人看到? 这是该交互的预期行为;如场景敏感,可在切换为明文 5 秒后自动恢复密文,只需在 setTimeout 里判断输入框仍为 text 时切回。
Q: 强度评分标准和业务不一致? score 函数是纯计算,按你的密码策略改门槛与正则即可,比如要求「必须含大写字母」时把该维度改为硬性校验。
Q: 输入框有浏览器自带的眼睛图标重复了? Edge 等浏览器会显示原生密码图标;给输入框加 ::-ms-reveal { display: none } 隐藏原生图标,避免双眼睛并存。
Q: 可以商用吗? 可以。本组件为粤喵自研原创代码,免费商用无需署名。
许可与来源
- 许可证:自研原创 —— 粤喵自研原创,可免费用于个人与商业项目,无需署名。查看来源公示与许可清单
- 来源:粤喵团队原创自研(从效果思路到代码实现均为独立完成,未直接复制第三方代码)
- 首次发布:2026-09-01 · 最近更新:2026-09-01
- 修改日志:2026-09-01 首次发布;2026-09-13 补充许可证与来源标注、复制按钮说明与法务页入口
- 纠错:联系页面 / min@cactus.asia,2 个工作日内核实处理
常见问题
这个组件可以商用吗?
可以。本组件为粤喵自研原创,可免费用于个人和商业项目,无需署名。
浏览器兼容性如何?
支持所有现代浏览器(Chrome / Firefox / Safari / Edge 最新版本)。旧版 IE 不支持 CSS 动画相关特性。
怎么修改动画参数?
直接调整 CSS 中的 animation-duration(时长)、animation-timing-function(缓动曲线)等属性即可,代码中有注释说明。