這篇我們來做一個簡單表單,即常見的注冊頁面吧~學習完這篇我們將學習到Input、label、CSS偽類、CSS入門、更多的JS操作等。。
一、首先明確需求:
直接模仿常見的注冊頁面,包括:用戶名、Email、性別(單選按鈕男/女)、出生日期(點擊出現日期表)、密碼、確認密碼和提交按鈕。
二、實現思路分析
表單結構設計:
使用HTML的
<form>
標簽作為容器每個輸入項用
<div>
包裹,包含<label>
和<input>
需要不同類型的輸入控件:文本、密碼、郵箱、單選、日期等
樣式設計:
添加響應式設計,適應不同屏幕
添加交互反饋(如聚焦效果)
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驗證) | 不需要值 |
備注:id
和name
經常設成相同,但作用不同:
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>
radio-group
?整個div包含兩個單選按鈕及其對應標簽單選按鈕(input radio)基本屬性(重要):
type="radio"
:定義這是一個單選按鈕id="male"
:唯一標識符,用于關聯labelname="gender"
:分組名稱,相同name的單選按鈕為一組value="male"
:選中時提交的值checked
:默認選中屬性
配套label標簽:
<label for="male">男</label>
for="male"
:與input的id對應,點擊label也能選中單選按鈕(前面有說!)"男":顯示給用戶看的文本
為什么男和女的name屬性相同?----相同
name
值使它們成為一組,只能選其中一個,如果name不同,就失去了單選的意義關于這塊的一些常見疑問:
????????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)先從第一個最外層的容器——form-container:
(以下都按三步法:確定設計圖-->思考過程-->實現代碼)
First:構建圖:
Second:思考過程:
需要白色背景 →?
background-color:
white;需要和里面的內容有間距 →?
padding(內邊距)
需要圓角效果 →?
border-radius
需要陰影提升層次感 →?
box-shadow,
一般都是用box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);在手機上占滿寬度,但不超過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和borderauto
:根據內容自動計算,可能不會占滿寬度
五、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;}
});