密码输入框“显示/隐藏”切换不能仅修改type属性,需先缓存value再切换并手动恢复,否则Safari等浏览器可能清空值;应避免setAttribute('type')和双input方案,须添加aria-label、aria-pressed及inputMode适配。

密码输入框如何实现“显示/隐藏”切换
直接改 type 属性就行,但浏览器会清空输入内容——这是最常被忽略的坑。Chrome、Firefox、Safari 在把 type="password" 切成 type="text" 时,只要 DOM 节点没被替换,值(input.value)其实一直保留着,只是渲染层做了掩码处理;但反过来切回去时,部分旧版 Safari 或某些安卓 WebView 会重置 value,所以不能只依赖 DOM 切换。
用 JavaScript 动态修改 type 的正确姿势
核心是:不直接赋值 input.type = "text",而是先缓存值,再切换,必要时手动恢复。尤其在 React/Vue 等框架里,直接改原生 type 可能触发重新挂载,导致焦点丢失或值清空。
- 原生 JS 推荐写法:
const input = document.querySelector('input[type="password"]');<br>const toggleBtn = document.querySelector('#toggle-btn');<br><br>toggleBtn.addEventListener('click', () => {<br> const isPassword = input.type === 'password';<br> // 先记下当前值(防 Safari 异常)<br> const currentValue = input.value;<br> input.type = isPassword ? 'text' : 'password';<br> // 切完再设一次 value(安全兜底)<br> input.value = currentValue;<br> // 手动聚焦,避免失焦<br> input.focus();<br>}); - 不要用
setAttribute('type', ...),它在部分浏览器中会强制重置value和selectionStart - 如果用了
autocomplete="off"或autocapitalize等属性,切换type后这些属性仍生效,无需额外处理
为什么不用两个 input 交替显示
有人用一个 type="password" 和一个 type="text" 互相 display: none 切换,看似稳妥,实则引入新问题:两次输入框都保留在 DOM 中,屏幕阅读器可能读出两遍,tabindex 顺序错乱,且需要同步管理两个元素的 value、placeholder、aria-label 等状态,维护成本高。
- 单 input 切换是标准做法,W3C ARIA 实践也推荐
- 必须加
aria-label或aria-controls指向切换按钮,例如: - 按钮需有
aria-pressed状态,并随切换实时更新:btn.setAttribute('aria-pressed', isPassword)
移动端软键盘行为差异要留意
Android Chrome 下,从 password 切成 text 后,软键盘不会自动切换为全键盘(仍可能是密码键盘),iOS 则通常会正确响应。这不是 bug,是系统对 inputmode 的优先级高于 type 的表现。
- 可显式加
inputmode="text"(仅对type="text"有效),但对password无效,所以切到text时建议同时设置:input.inputMode = 'text' - 部分安卓 WebView 不支持
inputmode,此时只能接受软键盘类型不完全匹配的事实 - 别监听
focus后再切type,否则 iOS 可能因 focus 时机问题导致键盘闪退
实际中最容易被绕开的是 input.value 的手动重置和 focus() 调用——很多人只写了 type 切换就以为完成了,结果在 Safari 上一点击“显示”,光标没了、值也没了。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











