使用JS编写用户信息采集表单
使用JS编写一个好看的用户信息收集表单
实现效果
实现代码
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>用户信息收集表单</title><style>body {font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;background-color: #f7f7f7;display: flex;justify-content: center;align-items: center;min-height: 100vh;margin: 0;padding: 20px;color: #333;}.form-container {background-color: white;border-radius: 8px;box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);width: 100%;max-width: 600px;padding: 30px;}h1 {color: #2c3e50;text-align: center;margin-bottom: 25px;font-weight: 500;}.form-group {margin-bottom: 20px;}label {display: block;margin-bottom: 8px;font-weight: 500;color: #2c3e50;}input[type="text"],input[type="number"] {width: 100%;padding: 12px;border: 1px solid #ddd;border-radius: 4px;font-size: 16px;transition: border-color 0.3s;}input:focus {outline: none;border-color: #3498db;box-shadow: 0 0 0 2px rgba(52, 152, 219, 0.2);}.error-input {border-color: #e74c3c;}.error-input:focus {box-shadow: 0 0 0 2px rgba(231, 76, 60, 0.2);}.radio-group, .checkbox-group {display: flex;gap: 20px;margin-top: 8px;}.radio-group label, .checkbox-group label {display: flex;align-items: center;gap: 8px;font-weight: normal;cursor: pointer;}input[type="radio"], input[type="checkbox"] {width: 18px;height: 18px;cursor: pointer;}.error-message {color: #e74c3c;font-size: 14px;margin-top: 6px;display: none;}button {background-color: #3498db;color: white;border: none;border-radius: 4px;padding: 14px 25px;font-size: 16px;cursor: pointer;transition: background-color 0.3s;display: block;width: 100%;}button:hover {background-color: #2980b9;}.output-container {margin-top: 30px;}.output-box {margin-bottom: 15px;}textarea {width: 100%;height: 120px;padding: 12px;border: 1px solid #ddd;border-radius: 4px;font-family: inherit;resize: vertical;}textarea:focus {outline: none;border-color: #3498db;}</style>
</head>
<body><div class="form-container"><h1>用户信息收集</h1><form id="userForm"><div class="form-group"><label for="name">Name:</label><input type="text" id="name" name="name"><div class="error-message" id="nameError"></div></div><div class="form-group"><label for="age">Age:</label><input type="number" id="age" name="age" min="0"><div class="error-message" id="ageError"></div></div><div class="form-group"><label>Gender</label><div class="radio-group"><label><input type="radio" name="gender" value="male"> Male</label><label><input type="radio" name="gender" value="female"> Female</label></div><div class="error-message" id="genderError"></div></div><div class="form-group"><label for="phone">Phone:</label><input type="text" id="phone" name="phone"></div><div class="form-group"><label>Hobbies</label><div class="checkbox-group"><label><input type="checkbox" name="hobby" value="reading"> Reading</label><label><input type="checkbox" name="hobby" value="sports"> Sports</label><label><input type="checkbox" name="hobby" value="music"> Music</label></div></div><button type="button" id="submitBtn">Submit</button></form><div class="output-container"><div class="output-box"><label>Output:</label><textarea id="output" readonly></textarea></div><div class="output-box"><label>Errors:</label><textarea id="errors" readonly></textarea></div></div></div><script>document.getElementById('submitBtn').addEventListener('click', function() {// Clear previous errors and outputsdocument.getElementById('output').value = '';document.getElementById('errors').value = '';// Clear error messages and input stylingdocument.querySelectorAll('.error-message').forEach(el => {el.textContent = '';el.style.display = 'none';});document.querySelectorAll('input').forEach(input => {input.classList.remove('error-input');});// Collect form dataconst name = document.getElementById('name').value.trim();const age = document.getElementById('age').value;const gender = document.querySelector('input[name="gender"]:checked')?.value;const phone = document.getElementById('phone').value.trim();// Get selected hobbiesconst hobbies = Array.from(document.querySelectorAll('input[name="hobby"]:checked')).map(hobby => hobby.value);// Validate formlet isValid = true;const errorMessages = [];// Validate Nameif (!name) {showError('nameError', 'Name cannot be blank');isValid = false;} else if (name.length > 15) {showError('nameError', 'Name cannot exceed 15 letters');isValid = false;}// Validate Ageif (!age) {showError('ageError', 'Age cannot be blank');isValid = false;} else {const ageNum = Number(age);if (isNaN(ageNum)) {showError('ageError', 'Age must be a number');isValid = false;} else if (ageNum < 0) {showError('ageError', 'Age cannot be negative');isValid = false;}}// Validate Genderif (!gender) {showError('genderError', 'Please select a gender');isValid = false;}// Process form or display errorsif (isValid) {// Format the output dataconst output = [`Name: ${name}`,`Age: ${age}`,`Gender: ${gender.charAt(0).toUpperCase() + gender.slice(1)}`,`Phone: ${phone || 'Not provided'}`,`Hobbies: ${hobbies.length > 0 ? hobbies.join(', ') : 'None selected'}`].join('\n');document.getElementById('output').value = output;} else {document.getElementById('errors').value = errorMessages.join('\n');}});// Helper function to display validation errorsfunction showError(elementId, message) {const errorElement = document.getElementById(elementId);errorElement.textContent = message;errorElement.style.display = 'block';// Highlight error inputs based on error typeif (elementId === 'nameError') {document.getElementById('name').classList.add('error-input');} else if (elementId === 'ageError') {document.getElementById('age').classList.add('error-input');} else if (elementId === 'genderError') {document.querySelectorAll('input[name="gender"]').forEach(el => {el.closest('label').classList.add('error-input');});}// Add error message to listerrorMessages.push(message);}</script>
</body>
</html>
🖌️ 视觉篇:颜值即正义
/* 魔法起始!整个页面变成优雅的居中考场 */
body {display: flex; /* 开启弹性布局魔法 */justify-content: center; /* 左右居中 */align-items: center; /* 垂直居中 */background-color: #f7f7f7; /* 温柔的灰色背景 */
}/* 表单容器秒变精致卡片 */
.form-container {box-shadow: 0 4px 12px rgba(0,0,0,0.1); /* 阴影:轻盈的漂浮感 */border-radius: 8px; /* 圆角:拒绝尖锐伤害 */
}
设计亮点:
- 输入框获得焦点时会出现蓝色光环
box-shadow: 0 0 0 2px rgba(52, 152, 219, 0.2)
,像被魔法棒点中一样✨ - 错误输入框秒变"番茄色"警告:
.error-input { border-color: #e74c3c }
- 提交按钮悬停时颜色变深,仿佛在说:“摸我一下试试?” 👆
📝 结构篇:HTML的智慧组合
<!-- 分组管理就像文件柜 -->
<div class="form-group"><label for="name">Name:</label> <!-- 贴心标签 --><input type="text" id="name"> <!-- 文本输入 --><div class="error-message"></div> <!-- 预留错误展示位 -->
</div><!-- 单选组横向排列不打架 -->
<div class="radio-group"><label><input type="radio" name="gender" value="male"> Male</label><label><input type="radio" name="gender" value="female"> Female</label>
</div><!-- 兴趣爱好像个自助餐 -->
<div class="checkbox-group"><label><input type="checkbox" name="hobby" value="reading"> Reading</label><!-- 其他选项... -->
</div>
小心机设计:
name
属性相同的radio自动成组(只能选一个)- 多选框
name
相同但允许多选,就像"我全都要!" 😏 - 错误提示一开始是隐藏的
display: none
,只在需要时跳出来
⚡ 互动篇:JavaScript的表演时刻
// 提交按钮:点我就开始表演!
submitBtn.addEventListener('click', () => {// 开场先清场打扫document.querySelectorAll('.error-message').forEach(el => {el.style.display = 'none';});// 开启侦探模式查案const name = nameInput.value.trim();if (!name) showError('nameError', '名字呢?你忘填啦!');else if (name.length > 15) showError('nameError', '名字太长记不住啦!');const age = ageInput.value;if (!age) showError('ageError', '年龄可是必考题!');else if (age < 0) showError('ageError', '咋的?来自未来?');
});
验证逻辑三巨头:
- 姓名:不能为空且≤15字符(超过时提示:“名字太长记不住啦!”)
- 年龄:必须为≥0的数字(负值会吐槽:“咋的?来自未来?”)
- 性别:必须选择(否则警告:“漏掉性别了亲!”)
成功后:
- 在
<textarea>
里美美展示用户信息 - 空手机号显示"Not provided",而不是尴尬的空白
- 爱好自动拼接:
hobbies.join(', ')
→ “Reading, Music”
💡 用户体验的闪光点
- 实时反馈:错误输入框秒变红色+文字提示(像有个小助手在耳边提醒)
- 包容设计:电话和爱好是可选项(用户:“终于不用编手机号了!”)
- 错误分屏展示:成功时只显示结果,失败时单独列出错误日志
- 性别单选组:排排站的设计比下拉菜单更直观
🚀 精妙代码技巧
// 1. 优雅获取单选值
const gender = document.querySelector('input[name="gender"]:checked')?.value;// 2. 获取多个复选框的黑科技
const hobbies = [...document.querySelectorAll('input[name="hobby"]:checked')].map(hobby => hobby.value);// 3. 错误处理函数(复用大师)
function showError(elementId, message) {const el = document.getElementById(elementId);el.textContent = message; el.style.display = 'block'; // 让错误信息闪亮登场
}
结语:这个表单会说话! 💬
这个表单最棒的地方在于:它懂用户更懂开发者。
- 用户看到的是优雅的卡片、聪明的提示和友好的反馈
- 开发者看到的是清晰的代码结构、灵活的验证逻辑和易于维护的设计
下次做表单时,记得把这些小心思偷走哦!这可比干巴巴的<input>
标签酷多啦~