表單校驗
本篇主要介紹使用 JavaScript 進行表單驗證。
表單驗證并不是 JavaScript 提供的某種特性,而是結合各種特性達到的一種目的,是需求的產物。
所有線上產品的表單幾乎都有驗證,如注冊時要求“用戶名 6-16 位”,驗證會由 JavaScript 來完成,通常為了安全性和準確性,服務端會再次做一遍驗證。
1. 驗證目標
表單用于收集信息,從 HTML 上講,表單內容使用 form
標簽進行包裹。
<form action="/login">
<label>
用戶名:<input type="text">
</label>
<label>
密碼:<input type="text">
</label>
<div>
<button type="submit">登入</button>
</div>
</form>
這就是一個相對簡單的表單,其中包含文本框(input標簽)與按鈕(button標簽),并使用 form 標簽進行包裹。
利用 form 標簽,再觸發其 submit 事件時,會將表單內容收集后提交個體 action
屬性配置的路徑。
單其實把 form 標簽去掉,在頁面上展示的效果幾乎是一樣的。
<label>
用戶名:<input type="text">
</label>
<label>
密碼:<input type="text">
</label>
<div>
<button type="submit">登入</button>
</div>·
所以自出現 AJAX 技術后,很多開發者都不再書寫 form 標簽,直接使用其他元素對表單內容進行包裹,因為業務上可能不需要使用 form 標簽的特性來提交表單。
其實不論是使用表單,還是不使用表單,表單的驗證都是針對所有表單項的,即輸入框、單選項、多選項等。
在表單提交之前,需要對寫著表單項的內容做校驗,然后攔截提交操作。
2. 獲取表單內容
獲取表單內容,實際上就是取到表單項對應的 DOM 節點的值。
獲取 DOM 節點的方式非常多,前面的章節也有介紹。
<style>
h3 {margin-top: 0;color: #4caf50;}
.login {width: 300px;padding: 32px;box-shadow: 2px 2px 10px rgba(0, 0, 0, .1);position: fixed;top: 40%;left: 50%;transform: translate(-50%, -50%);}
.form-item {display: flex;margin-bottom: 16px;border-bottom: 1px solid #ccc;}
.form-item .title {width: 70px;color: #666;font-size: 14px;}
.form-item .content {flex: 1;}
.form-item .content input {width: 100%;border: 0 none;padding: 2px 8px;outline: none;font-size: 16px;}
.login-btn {width: 100%;border: 0 none;background-color: #4caf50;color: white;margin-top: 16px;outline: none;height: 32px;}
.login-btn:active {background-color: #2da050;}
</style>
<form name="login-form" class="login">
<h3>登入</h3>
<label class="form-item">
<div class="title">用戶名</div>
<div class="content">
<input id="account" class="account" name="account" type="text">
</div>
</label>
<label class="form-item">
<div class="title">密碼</div>
<div class="content">
<input name="pwd" type="password">
</div>
</label>
<div>
<button class="login-btn" type="submit">登入</button>
</div>
</form>
<script>
var account1 = document.getElementById('account');
var account2 = document.getElementsByName('account');
var account3 = document.getElementsByClassName('account');
alert(account1 === account2[0]);
alert(account1 === account3[0]);
var account4 = document.forms['login-form']['account'];
alert(account1 === account4);
console.log(document.forms['login-form'].elements);
</script>
前三種獲取節點的方式讀者都已經熟悉了。
account4
的獲取方式稍微有點不一樣,document.forms 是文檔內的表單集合,其可以通過表單的 id 和 form 的屬性,取到具體的某個表單。
取到表單后,還可以直接使用表單項的 name 屬性取到對應的表單項,使用 elements
可以取到這個表單下的所有表單項。
3. 校驗表單項
獲取到表單項后,就可以對表單項的值做判斷了,如密碼必須是 6-16 位:
<style>
h3 {margin-top: 0;color: #4caf50;}
.login {width: 300px;padding: 32px;box-shadow: 2px 2px 10px rgba(0, 0, 0, .1);position: fixed;top: 40%;left: 50%;transform: translate(-50%, -50%);}
.form-item {display: flex;margin-bottom: 16px;border-bottom: 1px solid #ccc;}
.form-item .title {width: 70px;color: #666;font-size: 14px;}
.form-item .content {flex: 1;}
.form-item .content input {width: 100%;border: 0 none;padding: 2px 8px;outline: none;font-size: 16px;}
.login-btn {width: 100%;border: 0 none;background-color: #4caf50;color: white;margin-top: 16px;outline: none;height: 32px;}
.login-btn:active {background-color: #2da050;}
</style>
<form name="login-form" class="login" action="https://imooc.com">
<h3>登入</h3>
<label class="form-item">
<div class="title">用戶名</div>
<div class="content">
<input autocomplete="off" id="account" class="account" name="account" type="text">
</div>
</label>
<label class="form-item">
<div class="title">密碼</div>
<div class="content">
<input autocomplete="off" name="pwd" type="password">
</div>
</label>
<div>
<button class="login-btn" type="submit">登入</button>
</div>
</form>
<script>
var loginForm = document.forms['login-form'];
var pwdEle = loginForm.pwd;
loginForm.onsubmit = function(e) {
var pwd = pwdEle.value;
if (pwd.length < 6 || pwd.length > 16) {
alert('密碼長度 6-16');
return false; // 可以使用 return e.preventDefault() 代替
}
setTimeout(function() {
alert('登入成功,馬上跳轉!');
}, 1000);
};
</script>
這里獲取到了表單元素,同時給表單的事件處理器屬性 onsubmit
賦值,表示在表單被提交的時候做的事情。
在事件處理器中,通過輸入框的 value
屬性獲取到了輸入的值,對值進行了長度判斷,如果長度不正確則返回 false,表單則會終止提交。
如果正確,則會根據 form 標簽的 target 屬性進行提交。
需要注意的是,這里如果使用 addEventListener
來監聽 submit
事件,必須使用 preventDefault
來阻止默認事件,即阻止表單提交,不能使用 return false;
。
var loginForm = document.forms['login-form'];
var pwdEle = loginForm.pwd;
loginForm.addEventListener('submit', function(e) {
var pwd = pwdEle.value;
if (pwd.length < 6 || pwd.length > 16) {
alert('密碼長度 6-16');
e.preventDefault(); // 代替return false
return;
}
setTimeout(function() {
alert('登入成功,馬上跳轉!');
}, 1000);
});
4. 不使用 form 提交表單
不使用 form 標簽來提交表單,通常都是使用 AJAX 進行數據交互的情況。
這個時候就不需要攔截 form 的提交行為了。
<style>
h3 {margin-top: 0;color: #4caf50;}
.login {width: 300px;padding: 32px;box-shadow: 2px 2px 10px rgba(0, 0, 0, .1);position: fixed;top: 40%;left: 50%;transform: translate(-50%, -50%);}
.form-item {display: flex;margin-bottom: 16px;border-bottom: 1px solid #ccc;}
.form-item .title {width: 70px;color: #666;font-size: 14px;}
.form-item .content {flex: 1;}
.form-item .content input {width: 100%;border: 0 none;padding: 2px 8px;outline: none;font-size: 16px;}
.login-btn {width: 100%;border: 0 none;background-color: #4caf50;color: white;margin-top: 16px;outline: none;height: 32px;}
.login-btn:active {background-color: #2da050;}
</style>
<div class="login">
<h3>登入</h3>
<label class="form-item">
<div class="title">用戶名</div>
<div class="content">
<input autocomplete="off" id="account" class="account" name="account" type="text">
</div>
</label>
<label class="form-item">
<div class="title">密碼</div>
<div class="content">
<input autocomplete="off" name="pwd" type="password">
</div>
</label>
<div>
<button class="login-btn" type="button">登入</button>
</div>
</div>
<script>
var loginBtn = document.querySelector('.login-btn');
var pwdEle = document.querySelector('[name="pwd"]');
function login(cb) {
// 假裝登入花了 1 秒
setTimeout(function() {
alert('登入成功');
cb && cb();
}, 1000);
}
loginBtn.addEventListener('click', function() {
var pwd = pwdEle.value;
if (pwd.length < 6 || pwd.length > 16) {
alert('密碼長度 6-16');
return;
}
login(function() {
window.location.href = 'https://imooc.com';
});
});
</script>
使用這種方式,就可以自主控制流程,不需要再考慮 form 標簽的行為。
5. 小結
校驗表單非常常見,校驗表單的場景很多時候遠沒有本篇介紹的這么簡單,有時候數據校驗的格式非常復雜,需要結合正則、校驗算法等方式來解決,如嚴格的身份證驗證就需要結合身份證算法。
但表單的校驗總的來說都遵循獲取表單元素、獲取表單元素的值、對值進行判斷、根據判斷結果做下一步動作。