当前位置: 首页 > news >正文

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

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

实现效果

  • image-20250715233803822

实现代码

<!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', '咋的?来自未来?');
});

验证逻辑三巨头:

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

成功后:

  • <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>标签酷多啦~

http://www.xdnf.cn/news/1129807.html

相关文章:

  • 基于conda包的环境创建、激活、管理与删除
  • C++-linux系统编程 8.进程(二)exec函数族详解
  • 3.2数据库-关系代数-函数依赖-范式
  • IDEA中删除多余的jdk选项 【IDEA2024版】
  • Linux-【单体架构/分布式架构】
  • 李宏毅《生成式人工智能导论》 | 第9讲 AI Agent
  • AI问答-Token:在人工智能领域,Token 是模型处理文本的核心单元 / 最小可处理片段
  • cursor使用mcp连接mysql数据库,url方式
  • 基于Python的图像文字识别系统
  • Transformer是什么 - 李沐论文《Attention Is All You Need》精读
  • 数据怎么分层?从ODS、DW、ADS三大层一一拆解!
  • ESP32S3+VSCode+PlatformIO+Arduino+Freertos开发入门指南:基于Arduino框架的应用开发全流程
  • 基于按键开源MultiButton框架深入理解代码框架(一)(指针的深入理解与应用)
  • 137. 只出现一次的数字 II
  • python+selenium UI自动化初探
  • Linux操作系统之信号:保存与处理信号
  • 嵌入式Linux:进程间通信机制
  • URL 转静态 HTML 文件 API 数据接口
  • 算法入门:BFS与DFS详解(C++实现)
  • k8s之Attach 和 Mount
  • [AI8051U入门第三步]串口1使用-printf重定向(乱码解决办法)
  • 生产问题排查-数据库连接池耗尽
  • Linux 文件系统实现层详解:原理、结构与驱动衔接
  • 已知均数与标准差,如何生成一组正态分布数据?
  • 15.图像 模板轮廓检测
  • Unity音游开发全指南:模板与免费资源高效构建节奏游戏
  • Kafka——生产者消息分区机制原理剖析
  • 基于STM32与中航ZH-E3L字符卡通信在LED屏显示数据
  • 排序算法实战(上)
  • GitHub Pages+Jekyll 静态网站搭建(二)