Flex布局居中登录注册卡片需设body为flex容器并用min-height:100vh、justify-content/align-items:center;两表单共用容器并JS切换display;密码显示按钮应动态切换input type;提交按钮禁用后须在finally中恢复。
position: absolute
多数人一上来就用 top: 50% + transform: translateY(-50%) 居中,结果表单在不同屏幕高度下错位、响应式失效。Flex 是更稳的选择:
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
margin: 0;
background: #f5f7fa;
}注意必须设 min-height: 100vh(不是 height: 100vh),否则内容少时卡片仍会贴顶;align-items: center 对垂直居中生效,前提是父容器有明确高度。
display: none / block 而非重载页面真实项目里这两个表单共用同一页面,靠 JS 切换显示状态。关键点在于:两个 必须包裹在同一容器内,且初始状态要明确:
切换时只改
style.display,不操作 DOM 结构。这样能复用 CSS 样式、避免焦点丢失,也方便后续加淡入动画(用 opacity + transition 配合)。
input[type="password"] 的「显示密码」按钮必须用 type 切换而非伪造输入框常见错误是额外加一个 text 输入框覆盖在 password 上,导致表单提交取不到值、无障碍支持差。正确做法是直接改原 input 的 type:
const pwdInput = document.querySelector('#password');
const toggleBtn = document.querySelector('#toggle-password');
toggleBtn.addEventListener('click', () => {
const isPwd = pwdInput.type === 'password';
pwdInput.type = isPwd ? 'text' : 'password';
toggleBtn.textContent = isPwd ? '隐藏' : '显示';
});注意:IE 不支持动态改 type,但现代项目基本可忽略;另外务必同步更新按钮的 aria-label 和图标状态,否则读屏器会误读。
用户点击后立刻禁用按钮是基础,但仅加 disabled 属性还不够。必须配合服务端返回再决定是否恢复:
form.addEventListener('submit', async (e) => {
e.preventDefault();
const btn = e.target.querySelector('button[type="submit"]');
btn.disabled = true;
btn.textCo
ntent = '提交中...';
try {
await fetch('/api/login', { method: 'POST', body: new FormData(e.target) });
// 成功逻辑
} catch (err) {
// 显示错误(如:密码错误)
} finally {
btn.disabled = false;
btn.textContent = '登录';
}
});漏掉 finally 块会导致网络失败后按钮永远卡死;也不要只靠 .loading 类控制文字——用户刷新页面后类还在,但按钮实际可用,造成误导。