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

前端学习4:小白入门注册表单的制作(包括详细思考CSS、JS实现过程)

这篇我们来做一个简单表单,即常见的注册页面吧~学习完这篇我们将学习到Input、label、CSS伪类、CSS入门、更多的JS操作等。。

一、首先明确需求:

直接模仿常见的注册页面,包括:用户名、Email、性别(单选按钮男/女)、出生日期(点击出现日期表)、密码、确认密码和提交按钮。

二、实现思路分析

  1. 表单结构设计

    • 使用HTML的<form>标签作为容器

    • 每个输入项用<div>包裹,包含<label><input>

    • 需要不同类型的输入控件:文本、密码、邮箱、单选、日期等

  2. 样式设计

    • 添加响应式设计,适应不同屏幕

    • 添加交互反馈(如聚焦效果)

  3. JavaScript功能

    • 表单验证(前端验证)

    • 密码一致性检查

    • 日期选择器功能

    • 表单提交处理

 三、HTML结构:

<!DOCTYPE html>
<html>
<head><title>注册表单</title><link rel="stylesheet" href="form.css">
</head>
<body><div class="form-container"><h2>用户注册</h2><form id="registerForm"><!-- 用户名 --><div class="form-group"><label for="username">用户名:</label><input type="text" id="username" name="username" required><span class="error-message" id="usernameError"></span></div><!-- 邮箱 --><div class="form-group"><label for="email">Email:</label><input type="email" id="email" name="email" required><span class="error-message" id="emailError"></span></div><!-- 性别 --><div class="form-group"><label>性别:</label><div class="radio-group"><input type="radio" id="male" name="gender" value="male" checked><label for="male">男</label><input type="radio" id="female" name="gender" value="female"><label for="female">女</label></div></div><!-- 出生日期 --><div class="form-group"><label for="birthdate">出生日期:</label><input type="date" id="birthdate" name="birthdate" required></div><!-- 密码 --><div class="form-group"><label for="password">密码:</label><input type="password" id="password" name="password" required><span class="error-message" id="passwordError"></span></div><!-- 确认密码 --><div class="form-group"><label for="confirmPassword">确认密码:</label><input type="password" id="confirmPassword" name="confirmPassword" required><span class="error-message" id="confirmPasswordError"></span></div><button type="submit" class="submit-btn">注册</button></form></div><script src="form.js"></script>
</body>
</html>

1. <label>标签详解:

<label for="username">用户名:</label>

<input type="text" id="username" name="username" required>

<label>是表单元素的文字说明,可以提升用户体验:点击label文字也能聚焦到对应的输入框

  • for的值必须与对应<input>id完全一致,这样浏览器就知道这个label是描述哪个input的

  • 点击"用户名:"文字时,会自动聚焦到id为"username"的输入框

2. <input>标签详解

<input type="text" id="username" name="username" required>

 关键属性解析

属性作用示例值
type定义输入框类型text(文本)、password(密码)、email(邮箱)
id唯一标识符,用于label关联和CSS/JS操作username
name表单提交时的字段名(服务器接收的参数名)username
required表示必填项(HTML5验证)不需要值

备注:idname经常设成相同,但作用不同:

  • id是给浏览器/DOM用的

  • name是给表单提交到服务器用的(是服务器接收的参数名)

3. 错误提示<span>的作用

<span class="error-message" id="usernameError"></span>

        这个空容器用来显示JS验证的错误提示。

4.性别的单选按钮(radio)详解:

<div class="form-group">
<label>性别:</label>
<div class="radio-group">
<input type="radio" id="male" name="gender" value="male" checked>
        <label for="male">男</label>
<input type="radio" id="female" name="gender" value="female">
        <label for="female">女</label>
</div>
</div>

  1. radio-group 整个div包含两个单选按钮及其对应标签

  2. 单选按钮(input radio)基本属性(重要):

    • type="radio":定义这是一个单选按钮

    • id="male":唯一标识符,用于关联label

    • name="gender":分组名称,相同name的单选按钮为一组

    • value="male":选中时提交的值

    • checked:默认选中属性

  3. 配套label标签:

    • <label for="male">男</label>

      • for="male":与input的id对应,点击label也能选中单选按钮(前面有说!)

      • "男":显示给用户看的文本

  4. 为什么男和女的name属性相同?----相同name值使它们成为一组,只能选其中一个,如果name不同,就失去了单选的意义

  5. 关于这块的一些常见疑问:

        Q1:为什么不用select下拉菜单而用radio?

        A1:radio适合选项较少(2-5个)且需要直观展示所有选项的情况,select适合选项较多的情况。

        Q2:checked属性可以加在多个radio上吗?
A2:不可以,同name的radio组中只有一个能被checked,浏览器会自动处理。

        Q3:如何设置默认不选中任何选项?
A3:去掉所有radio的checked属性即可,但通常建议设置一个默认选中项。

        Q4:value属性是必须的吗?
A4:是的,否则表单提交时该字段的值会是"on"而不是你期望的值。


四、CSS结构:

本次必须讲解下CSS的编写的思路!(严肃脸)

步骤1:分析页面结构

前面我们写好了html,搭好了结构,现在装修下,但是怎么“装修”呢?先分析下我们html页面的一个整体结构涉及到的class=“xxx”,可以发现,基本都是这样的结构:

表单容器(form-container)
├─ 标题(h2)
└─ 表单(form)
├─ 表单项1(form-group)
│  ├─ 标签(label)
│  └─ 输入框(input)
└─ 表单项2........

 步骤2:按照思路:从外到内,从大到小编写CSS

  1. 先写最外层容器样式

  2. 然后写内部大区块

  3. 最后处理细节和小元素


脑子里先构建好大致的长什么样?比如我们现在就做最简单的一个表:

(1)先从第一个最外层的容器——form-container:

(以下都按三步法:确定设计图-->思考过程-->实现代码)

First:构建图:

Second:思考过程

  1. 需要白色背景 → background-color:white;

  2. 需要和里面的内容有间距 → padding(内边距)

  3. 需要圆角效果 → border-radius

  4. 需要阴影提升层次感 → box-shadow一般都是用box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);

  5. 在手机上占满宽度,但不超过500px → width:100% + max-width

Third:总结就是:

.form-container {background-color: white;padding: 30px;border-radius: 8px;box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);width: 100%;                  /* 宽度 */max-width: 500px;             /* 最大宽度 */
}
 (2) 表单项.form-group

First:构建图:

Second:思考过程: 

  • 每个表单项(用户名、邮箱、密码...)之间需要垂直间距

  • 不需要左右margin因为父容器已经有padding

  • 不需要上margin因为第一个元素不需要顶部间距

Third:总结就是:

.form-group {margin-bottom: 20px;
}

(3)标签label:

其次就是标签这一块,即“用户名”、“密码”等等这一块搞个统一的样式:

First:构建图:

Second:思考过程:  

  • 我们需要这独占一行 ,而<label>元素默认属于行内元素,所以我们需要转成块级元素(搞不明白的去学我之前的文章块级和行内的区别):display: block;
  • 然后文字跟框有距离:margin-bottom(如图中的橙色部分)
  • 字体设置为粗体,醒目:font-weight: bold;
  • 字的颜色设置为黑色:color

Third:总结就是:

label {display: block;margin-bottom: 8px;font-weight: bold;color: #555;
}

(4)输入框样式 (重要)

先学习下新写法——属性选择器input[type="xxx"]:精确选择特定类型的input

First:构建图:

Second:思考过程:   

  • 框需要充满父容器 :width:100%
  • 文字与框之间需要距离,即内边距padding
  • 框我们想要黑边的、圆角的:border和border-radius,一般大圆角就是8px,小圆角就是4px
  • 输入的内容的字体我们也可以控制下:font-size
  • 还有一个重要的点,因为我们需要框刚好去充满父容器,所以需要保证内边距+边框的宽度是不会影响整个总宽度的:box-sizing: border-box

Third:总结就是:

input[type="text"],
input[type="email"],
input[type="password"],
input[type="date"] {width: 100%;                  /* 充满父容器 */padding: 10px;                /* 内边距 */border: 1px solid #ddd;       /* 边框 */border-radius: 4px;           /* 圆角 */font-size: 16px;              /* 字体大小 */box-sizing: border-box;       /* 盒模型计算方式:让width包含padding和border */
}

 (5)单选按钮组:

First:构建图:

Second:思考过程:   

先看整个radio-group(包括了按钮和标签):

  • 我们想要水平放置按钮: display: flex;
  • 两个按钮需要有间距:gap
  • 与上方的标签“性别”需要有距离(外边距):margin-top(图中橙色的那部分)

再看radio-group的标签(也就是“男”,“女”):

  • 同样也需要水平放置:display: flex;
  • 与上一个按钮之间需要间距,不然贴在一起不好看:gap

好,看下结果却是:

发现“男”、“女”两个字“飘”上去了,有个margin-bottom: 8px;存在,对不齐,太丑了。

为什么会有margin-bottom: 8px这个存在呢?因为男女也是属于label,而前面我们设置了label中的margin-bottom: 8px;,因此这个男女也被应用上了,所以!我们需要在这个男女这个标签单独去加个margin-bottom: 0;!

还有同样的取消掉加粗:font-weight: normal;

Third:总结就是:

.radio-group {display: flex;     /* 使用flex布局让单选按钮水平排列 */gap: 20px;             /* 设置20px的间距 */margin-top: 8px;     /* 与上方标签的间距 */
}.radio-group label {display: flex;gap: 5px;          /* 文字和按钮间距 */font-weight: normal;          /* 取消加粗 */margin-bottom: 0;
}

 总结一个小的思考路线:

是否需要布局? → 是 → 需要水平排列吗? → 是 → display: flex
│                                                     → 否 → display: block
→ 否 → 需要间距吗? → 是 → margin/padding/gap
→ 否 → 需要美化吗? → 是 → 颜色/圆角/阴影... 

CSS的全部代码(form.css):

body {font-family: 'Arial', sans-serif;background-color: #f5f5f5;display: flex;justify-content: center;align-items: center;min-height: 100vh;margin: 0;
}.form-container {background-color: white;padding: 30px;border-radius: 8px;box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);width: 100%;                  /* 宽度 */max-width: 500px;             /* 最大宽度 */
}h2 {text-align: center;color: #333;margin-bottom: 20px;
}.form-group {margin-bottom: 20px;
}label {display: block;margin-bottom: 8px;font-weight: bold;color: #555;
}input[type="text"],
input[type="email"],
input[type="password"],
input[type="date"] {width: 100%;                  /* 充满父容器 */padding: 10px;                /* 内边距 */border: 1px solid #ddd;       /* 边框 */border-radius: 4px;           /* 圆角 */font-size: 16px;              /* 字体大小 */box-sizing: border-box;   /* 确保内边距和边框不影响总宽度 */
}input:focus {               /* input:focus	选择元素输入后具有焦点 */outline: none;                /* 移除默认焦点轮廓线 */border-color: #4a90e2;         /* 聚焦时的边框颜色 */box-shadow: 0 0 5px rgba(74, 144, 226, 0.5);  /* 添加聚焦时的阴影效果 */
}.radio-group {display: flex;     /* 使用flex布局让单选按钮水平排列 */gap: 20px;             /* 设置20px的间距 */margin-top: 8px;     /* 与上方标签的间距 */
}.radio-group label {display: flex;gap: 5px;          /* 文字和按钮间距 */font-weight: normal;          /* 取消加粗 */margin-bottom: 0;
}.error-message {color: #e74c3c;font-size: 14px;margin-top: 5px;display: block;
}.submit-btn {width: 100%;padding: 12px;background-color: #4a90e2;color: white;border: none;   /* 移除默认边框 */border-radius: 4px;font-size: 16px;cursor: pointer;        /* 鼠标悬停时显示手型光标 */transition: background-color 0.3s;
}.submit-btn:hover {background-color: #357ab8;
}

 一个答疑总结:

Q:width:100%和width:auto有什么区别?
A:

  • 100%强制撑满父容器,包含padding和border

  • auto根据内容自动计算,可能不会占满宽度


五、JavaScript功能实现:

总体流程:

首先还是我们常用的DOMContentLoaded事件(还是那句话:让HTML文档完全加载和解析完成后,再执行里面的代码,这样可以确保我们能找到DOM元素。)

document.addEventListener('DOMContentLoaded', function() {// 代码在这里执行
});

这一块的逻辑可以想想:当用户点击提交表单的按钮时,系统直接获取用户输入的所有数据,进行数据有效性的验证,然后提示注册成功,最后重置表单。大概就是这样的一个流程了。

 第一步:处理点击提交按钮的事件监听:

form.addEventListener('submit', function(e) {e.preventDefault(); // 阻止表单默认提交行为
});

这里我们先写上阻止表单默认的提交行为(页面跳转),这样我们就能用JavaScript后续处理表单数据。

第二步: 获取用户输入的所有数据,需要使用到键值对,比如username对应document.getElementById('username').value,这里的.value可以拿到用户输入的值,因此我们直接把这些一个个键值对整合到一个对象里面:

            // 获取表单数据const formData = {username: document.getElementById('username').value,email: document.getElementById('email').value,gender: document.querySelector('input[name="gender"]:checked').value,birthdate: document.getElementById('birthdate').value,password: document.getElementById('password').value};

formData对象的作用是收集表单数据,把各个表单字段的值(如用户名、邮箱)整合到一个对象中。

 第三步:数据有效性验证,这里我们是想校验用户输入的用户名比如要求在4-20个字符内等等要求,所以我们需要对每个字段数据去校验。把校验的功能单独分出来,后续再具体写,这里先假装调用函数:

if (validateForm()) {
。。。
}

第四步:提示注册成功:

alert('注册成功!');

第五步:重置表单: 

form.reset();

整体代码如下:

document.addEventListener('DOMContentLoaded', function() {const form = document.getElementById('registerForm');// 表单提交事件处理form.addEventListener('submit', function(e) {e.preventDefault(); // 阻止表单默认提交行为// 验证表单if (validateForm()) {// 获取表单数据const formData = {username: document.getElementById('username').value,email: document.getElementById('email').value,// 使用CSS选择器找到被选中的单选按钮,获取其valuegender: document.querySelector('input[name="gender"]:checked').value,birthdate: document.getElementById('birthdate').value,password: document.getElementById('password').value};// 这里通常是发送到服务器的代码console.log('表单数据:', formData);alert('注册成功!');form.reset(); // 重置表单}});

表单验证函数validateForm():

然后我们具体来写表单验证函数validateForm(),先定义函数function  validateForm(){...}

定义一个标志,比如验证用户输入的用户名是4-20个字符里面,就设置标志为true,验证密码至少6个字符,就设置为true,一一验证,最后返回标志,这样回到前面我们的if (validateForm())就可以判断是不是true,从而走下面的步骤。

// 表单验证函数function validateForm() {let isValid = true;// 验证用户名const username = document.getElementById('username').value;if (username.length < 4 || username.length > 20) {document.getElementById('usernameError').textContent = '用户名需4-20个字符';isValid = false;}// 验证邮箱const email = document.getElementById('email').value;const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;if (!emailRegex.test(email)) {document.getElementById('emailError').textContent = '请输入有效的邮箱地址';isValid = false;}// 验证密码const password = document.getElementById('password').value;if (password.length < 6) {document.getElementById('passwordError').textContent = '密码至少6个字符';isValid = false;}// 验证确认密码const confirmPassword = document.getElementById('confirmPassword').value;if (confirmPassword !== password) {document.getElementById('confirmPasswordError').textContent = '两次输入的密码不一致';isValid = false;}return isValid;}

总结一下前面的代码都在干嘛?-----就是用户点击提交按钮,我们去校验每个字段是不是合乎我们自定义的规则的?是就提示“注册成功”。

但是我们想继续实时校验每个字段数据呢?就是比如用户输入第一个用户名不符合规则,就提示,而不是等到点击提交按钮了再统一提示。

全部代码如下(form.js):

// script.js
document.addEventListener('DOMContentLoaded', function() {const form = document.getElementById('registerForm');// 表单提交事件处理form.addEventListener('submit', function(e) {e.preventDefault(); // 阻止表单默认提交行为// 验证表单if (validateForm()) {// 获取表单数据const formData = {username: document.getElementById('username').value,email: document.getElementById('email').value,gender: document.querySelector('input[name="gender"]:checked').value,birthdate: document.getElementById('birthdate').value,password: document.getElementById('password').value};// 这里通常是发送到服务器的代码console.log('表单数据:', formData);alert('注册成功!');form.reset(); // 重置表单}});// 实时验证用户名document.getElementById('username').addEventListener('input', function() {const username = this.value;const errorElement = document.getElementById('usernameError');if (username.length < 4) {errorElement.textContent = '用户名至少4个字符';} else if (username.length > 20) {errorElement.textContent = '用户名不能超过20个字符';} else {errorElement.textContent = '';}});// 实时验证邮箱document.getElementById('email').addEventListener('input', function() {const email = this.value;const errorElement = document.getElementById('emailError');const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;if (!emailRegex.test(email)) {errorElement.textContent = '请输入有效的邮箱地址';} else {errorElement.textContent = '';}});// 密码验证document.getElementById('password').addEventListener('input', function() {const password = this.value;const errorElement = document.getElementById('passwordError');if (password.length < 6) {errorElement.textContent = '密码至少6个字符';} else {errorElement.textContent = '';}});// 确认密码验证document.getElementById('confirmPassword').addEventListener('input', function() {const confirmPassword = this.value;const password = document.getElementById('password').value;const errorElement = document.getElementById('confirmPasswordError');if (confirmPassword !== password) {errorElement.textContent = '两次输入的密码不一致';} else {errorElement.textContent = '';}});// 表单验证函数function validateForm() {let isValid = true;// 验证用户名const username = document.getElementById('username').value;if (username.length < 4 || username.length > 20) {document.getElementById('usernameError').textContent = '用户名需4-20个字符';isValid = false;}// 验证邮箱const email = document.getElementById('email').value;const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;if (!emailRegex.test(email)) {document.getElementById('emailError').textContent = '请输入有效的邮箱地址';isValid = false;}// 验证密码const password = document.getElementById('password').value;if (password.length < 6) {document.getElementById('passwordError').textContent = '密码至少6个字符';isValid = false;}// 验证确认密码const confirmPassword = document.getElementById('confirmPassword').value;if (confirmPassword !== password) {document.getElementById('confirmPasswordError').textContent = '两次输入的密码不一致';isValid = false;}return isValid;}
});

六、运行结果图:

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

相关文章:

  • uniapp语音播报天气预报微信小程序
  • 格密码--数学基础--02基变换、幺模矩阵与 Hermite 标准形
  • 从UI设计到数字孪生实战应用:构建智慧金融的风险评估与预警平台
  • 使用 SSH 连接 GitHub
  • 飞算 JavaAI 深度体验:开启 Java 开发智能化新纪元
  • 速学 RocketMQ
  • 基于定制开发开源AI智能名片与S2B2C商城小程序的旅游日志创新应用研究
  • FPGA实现SDI转LVDS视频发送,基于GTX+OSERDES2原语架构,提供2套工程源码和技术支持
  • Maui劝退:用windows直接真机调试iOS,无须和Mac配对
  • leetcode:518. 零钱兑换 II[完全背包]
  • Python 类型注解实战:`Optional` 与安全数据处理的艺术
  • 静态路由综合实验
  • GitHub敏感信息收集与防御指南
  • 人大金仓下载安装教程总结
  • 时间显示 蓝桥云课Java
  • 安卓应用启动崩溃的问题排查记录
  • P1722 矩阵 II 题解 DFS深度优先遍历与卡特兰数(Catalan number)解
  • 【实战】使用 ELK 搭建 Spring Boot Docker 容器日志监控系统
  • 【三维生成】FlashDreamer:基于扩散模型的单目图像到3D场景
  • 力扣-54.螺旋矩阵
  • “Datawhale AI夏令营”基于带货视频评论的用户洞察挑战赛
  • 敏捷测试中的质量闸门如何设置?
  • 【RL-VLM-F】算法框架图绘图学习笔记
  • 【PyTorch】PyTorch中的数据预处理操作
  • Java 与 MySQL 性能优化:MySQL连接池参数优化与性能提升
  • 7月10号总结 (1)
  • HTTP核心基础详解(附实战要点)
  • Android开发中几种scope的对比
  • 【TCP/IP】12. 文件传输协议
  • 力扣-73.矩阵置零