使用JS编写用户信息采集表单

使用JS编写一个好看的用户信息收集表单

实现效果

实现代码

html 复制代码
<!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 outputs
            document.getElementById('output').value = '';
            document.getElementById('errors').value = '';
            
            // Clear error messages and input styling
            document.querySelectorAll('.error-message').forEach(el => {
                el.textContent = '';
                el.style.display = 'none';
            });
            
            document.querySelectorAll('input').forEach(input => {
                input.classList.remove('error-input');
            });
            
            // Collect form data
            const 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 hobbies
            const hobbies = Array.from(document.querySelectorAll('input[name="hobby"]:checked'))
                                 .map(hobby => hobby.value);
            
            // Validate form
            let isValid = true;
            const errorMessages = [];
            
            // Validate Name
            if (!name) {
                showError('nameError', 'Name cannot be blank');
                isValid = false;
            } else if (name.length > 15) {
                showError('nameError', 'Name cannot exceed 15 letters');
                isValid = false;
            }
            
            // Validate Age
            if (!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 Gender
            if (!gender) {
                showError('genderError', 'Please select a gender');
                isValid = false;
            }
            
            // Process form or display errors
            if (isValid) {
                // Format the output data
                const 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 errors
        function showError(elementId, message) {
            const errorElement = document.getElementById(elementId);
            errorElement.textContent = message;
            errorElement.style.display = 'block';
            
            // Highlight error inputs based on error type
            if (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 list
            errorMessages.push(message);
        }
    </script>
</body>
</html>

🖌️ 视觉篇:颜值即正义

css 复制代码
/* 魔法起始!整个页面变成优雅的居中考场 */
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的智慧组合

js 复制代码
<!-- 分组管理就像文件柜 -->
<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的表演时刻

js 复制代码
// 提交按钮:点我就开始表演!
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', '咋的?来自未来?');
});

验证逻辑三巨头:

  1. 姓名:不能为空且≤15字符(超过时提示:"名字太长记不住啦!")
  2. 年龄:必须为≥0的数字(负值会吐槽:"咋的?来自未来?")
  3. 性别:必须选择(否则警告:"漏掉性别了亲!")

成功后:

  • <textarea>里美美展示用户信息
  • 空手机号显示"Not provided",而不是尴尬的空白
  • 爱好自动拼接:hobbies.join(', ') → "Reading, Music"

💡 用户体验的闪光点

  • 实时反馈:错误输入框秒变红色+文字提示(像有个小助手在耳边提醒)
  • 包容设计:电话和爱好是可选项(用户:"终于不用编手机号了!")
  • 错误分屏展示:成功时只显示结果,失败时单独列出错误日志
  • 性别单选组:排排站的设计比下拉菜单更直观

🚀 精妙代码技巧

js 复制代码
// 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>标签酷多啦~