最可靠方案是直接赋值input.type="text"或"password",而非setAttribute;需提前缓存value和光标位置,切换后手动恢复focus与selectionRange,并同步更新aria-pressed和aria-label。

点击按钮切换 type="password" 和 type="text"
直接改 input 的 type 属性是最常用也最可靠的做法。现代浏览器(Chrome、Firefox、Safari、Edge)都支持运行时动态修改 type,但注意:IE10+ 才完全兼容,IE9 及更早版本会抛出错误(InvalidStateError 或静默失败)。
实操建议:
- 用
input.type = 'text'切换可见,input.type = 'password'切回隐藏,不要用setAttribute—— 某些旧版 Safari 对setAttribute('type', ...)支持不稳定 - 切换前先保存焦点状态,否则 iOS Safari 会在切为
text后自动弹出键盘但光标丢失 - 按钮图标建议用 SVG 或 Unicode ✅/?,避免依赖外部字体加载失败导致空白
为什么不能用 inputMode 或 autocomplete 实现可见性控制?
inputmode 只影响软键盘类型(比如设为 "numeric" 弹数字键盘),autocomplete 控制表单记忆行为,二者都不改变密码掩码逻辑。试图靠它们“绕过 type 切换”只会白忙活。
常见误操作:
立即学习“前端免费学习笔记(深入)”;
- 把
input包在div里用伪元素盖一层“明文”,实际值仍是密文 → 复制粘贴、JS 获取.value还是星号 - 用两个 input 重叠切换显示 → 增加 DOM 复杂度,焦点管理易出错,且无障碍支持差(AT 工具可能读两次)
React/Vue 中处理 type 切换的注意事项
框架里直接改 type 可能触发重新挂载(尤其 React 18 严格模式下),导致输入框失焦或光标跳到开头。
推荐写法:
- React:用
useState控制type,但配合useRef保存焦点位置,切换后手动inputRef.current?.focus() - Vue:绑定
:type,加key(如:key="isPasswordVisible")强制重建 input,比复用更稳 - 都别用
v-model/value+onChange双向绑定后又手动 set state → 容易因渲染时机导致值滞后
无障碍与安全边界必须守住
切换按钮本身要带 aria-pressed 状态,且 label 必须明确表达当前模式(例如“显示密码”/“隐藏密码”),不能只写“眼睛图标”。
容易被忽略的点:
- 用户切换为明文后,若离开页面再返回,浏览器可能自动恢复为
password类型(尤其是 Chrome autofill 场景)→ 需监听pagehide/pageshow重置状态 - 明文状态下,
input的value仍可被 JS 任意读取,但绝不能发到日志、埋点或未加密 API → 切换只是 UX 优化,不改变传输/存储安全性 - 移动端双击复制时,iOS 会优先复制明文内容,Android 部分机型则复制原始值(取决于系统版本)→ 测试真机,别只信模拟器



















