表單校驗(yàn)
本篇主要介紹使用 JavaScript 進(jìn)行表單驗(yàn)證。
表單驗(yàn)證并不是 JavaScript 提供的某種特性,而是結(jié)合各種特性達(dá)到的一種目的,是需求的產(chǎn)物。
所有線(xiàn)上產(chǎn)品的表單幾乎都有驗(yàn)證,如注冊(cè)時(shí)要求“用戶(hù)名 6-16 位”,驗(yàn)證會(huì)由 JavaScript 來(lái)完成,通常為了安全性和準(zhǔn)確性,服務(wù)端會(huì)再次做一遍驗(yàn)證。
1. 驗(yàn)證目標(biāo)
表單用于收集信息,從 HTML 上講,表單內(nèi)容使用 form
標(biāo)簽進(jìn)行包裹。
<form action="/login">
<label>
用戶(hù)名:<input type="text">
</label>
<label>
密碼:<input type="text">
</label>
<div>
<button type="submit">登入</button>
</div>
</form>
這就是一個(gè)相對(duì)簡(jiǎn)單的表單,其中包含文本框(input標(biāo)簽)與按鈕(button標(biāo)簽),并使用 form 標(biāo)簽進(jìn)行包裹。
利用 form 標(biāo)簽,再觸發(fā)其 submit 事件時(shí),會(huì)將表單內(nèi)容收集后提交個(gè)體 action
屬性配置的路徑。
單其實(shí)把 form 標(biāo)簽去掉,在頁(yè)面上展示的效果幾乎是一樣的。
<label>
用戶(hù)名:<input type="text">
</label>
<label>
密碼:<input type="text">
</label>
<div>
<button type="submit">登入</button>
</div>·
所以自出現(xiàn) AJAX 技術(shù)后,很多開(kāi)發(fā)者都不再書(shū)寫(xiě) form 標(biāo)簽,直接使用其他元素對(duì)表單內(nèi)容進(jìn)行包裹,因?yàn)闃I(yè)務(wù)上可能不需要使用 form 標(biāo)簽的特性來(lái)提交表單。
其實(shí)不論是使用表單,還是不使用表單,表單的驗(yàn)證都是針對(duì)所有表單項(xiàng)的,即輸入框、單選項(xiàng)、多選項(xiàng)等。
在表單提交之前,需要對(duì)寫(xiě)著表單項(xiàng)的內(nèi)容做校驗(yàn),然后攔截提交操作。
2. 獲取表單內(nèi)容
獲取表單內(nèi)容,實(shí)際上就是取到表單項(xiàng)對(duì)應(yīng)的 DOM 節(jié)點(diǎn)的值。
獲取 DOM 節(jié)點(diǎn)的方式非常多,前面的章節(jié)也有介紹。
<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">用戶(hù)名</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>
前三種獲取節(jié)點(diǎn)的方式讀者都已經(jīng)熟悉了。
account4
的獲取方式稍微有點(diǎn)不一樣,document.forms 是文檔內(nèi)的表單集合,其可以通過(guò)表單的 id 和 form 的屬性,取到具體的某個(gè)表單。
取到表單后,還可以直接使用表單項(xiàng)的 name 屬性取到對(duì)應(yīng)的表單項(xiàng),使用 elements
可以取到這個(gè)表單下的所有表單項(xiàng)。
3. 校驗(yàn)表單項(xiàng)
獲取到表單項(xiàng)后,就可以對(duì)表單項(xiàng)的值做判斷了,如密碼必須是 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">用戶(hù)名</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('密碼長(zhǎng)度 6-16');
return false; // 可以使用 return e.preventDefault() 代替
}
setTimeout(function() {
alert('登入成功,馬上跳轉(zhuǎn)!');
}, 1000);
};
</script>
這里獲取到了表單元素,同時(shí)給表單的事件處理器屬性 onsubmit
賦值,表示在表單被提交的時(shí)候做的事情。
在事件處理器中,通過(guò)輸入框的 value
屬性獲取到了輸入的值,對(duì)值進(jìn)行了長(zhǎng)度判斷,如果長(zhǎng)度不正確則返回 false,表單則會(huì)終止提交。
如果正確,則會(huì)根據(jù) form 標(biāo)簽的 target 屬性進(jìn)行提交。
需要注意的是,這里如果使用 addEventListener
來(lái)監(jiān)聽(tīng) submit
事件,必須使用 preventDefault
來(lái)阻止默認(rèn)事件,即阻止表單提交,不能使用 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('密碼長(zhǎng)度 6-16');
e.preventDefault(); // 代替return false
return;
}
setTimeout(function() {
alert('登入成功,馬上跳轉(zhuǎn)!');
}, 1000);
});
4. 不使用 form 提交表單
不使用 form 標(biāo)簽來(lái)提交表單,通常都是使用 AJAX 進(jìn)行數(shù)據(jù)交互的情況。
這個(gè)時(shí)候就不需要攔截 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">用戶(hù)名</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('密碼長(zhǎng)度 6-16');
return;
}
login(function() {
window.location.href = 'https://imooc.com';
});
});
</script>
使用這種方式,就可以自主控制流程,不需要再考慮 form 標(biāo)簽的行為。
5. 小結(jié)
校驗(yàn)表單非常常見(jiàn),校驗(yàn)表單的場(chǎng)景很多時(shí)候遠(yuǎn)沒(méi)有本篇介紹的這么簡(jiǎn)單,有時(shí)候數(shù)據(jù)校驗(yàn)的格式非常復(fù)雜,需要結(jié)合正則、校驗(yàn)算法等方式來(lái)解決,如嚴(yán)格的身份證驗(yàn)證就需要結(jié)合身份證算法。
但表單的校驗(yàn)總的來(lái)說(shuō)都遵循獲取表單元素、獲取表單元素的值、對(duì)值進(jìn)行判斷、根據(jù)判斷結(jié)果做下一步動(dòng)作。