# ===== CodeLab: js-forms ===== # 以下代码片段按文章出现顺序拼接, 共 6 段 # ----- 片段 1 (text) -----
# ----- 片段 2 (javascript) ----- const form = document.getElementById('registerForm'); form.addEventListener('submit', function (event) { event.preventDefault(); const data = new FormData(form); const values = Object.fromEntries(data.entries()); console.log(values); }); # ----- 片段 3 (javascript) ----- const rules = { username: /^[a-zA-Z0-9_]{3,16}$/, email: /^[\w.-]+@[\w-]+(\.[\w-]+)+$/, password: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,20}$/ }; function validate(field, value) { if (!value) { return field === 'username' ? '请输入用户名' : '此项不能为空'; } if (!rules[field].test(value)) { const messages = { username: '用户名需为 3-16 位字母、数字或下划线', email: '邮箱格式不正确', password: '密码需 8-20 位,且同时包含大小写字母和数字' }; return messages[field]; } return ''; } console.log(validate('username', 'linwan')); console.log(validate('email', 'lin@example.com')); console.log(validate('password', 'abc')); console.log(validate('password', 'Abc12345')); # ----- 片段 4 (javascript) ----- function bindLiveValidation(inputId, errorId, field) { const input = document.getElementById(inputId); const error = document.getElementById(errorId); input.addEventListener('input', function () { const message = validate(field, input.value.trim()); error.textContent = message; input.classList.toggle('invalid', Boolean(message)); }); } bindLiveValidation('username', 'usernameError', 'username'); bindLiveValidation('email', 'emailError', 'email'); bindLiveValidation('password', 'passwordError', 'password'); # ----- 片段 5 (javascript) ----- form.addEventListener('submit', async function (event) { event.preventDefault(); const data = new FormData(form); const values = Object.fromEntries(data.entries()); values.username = values.username.trim(); values.email = values.email.trim(); const errors = {}; for (const field of ['username', 'email', 'password']) { const message = validate(field, values[field]); if (message) { errors[field] = message; } } if (values.password !== values.confirm) { errors.confirm = '两次输入的密码不一致'; } if (Object.keys(errors).length > 0) { console.log('校验失败:', errors); return; } const button = form.querySelector('button[type="submit"]'); button.disabled = true; button.textContent = '提交中…'; try { const response = await fetch('/api/register', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(values) }); if (!response.ok) { throw new Error('注册失败,请稍后再试'); } console.log('注册成功!'); } catch (err) { console.error(err.message); } finally { button.disabled = false; button.textContent = '注册'; } }); # ----- 片段 6 (javascript) ----- function showErrors(errors) { for (const [field, message] of Object.entries(errors)) { const errorEl = document.getElementById(field + 'Error'); if (errorEl) { errorEl.textContent = message; } const input = document.getElementById(field); if (input) { input.classList.toggle('invalid', Boolean(message)); } } } showErrors({ username: '用户名已被占用', email: '邮箱格式不正确' });