內(nèi)容是《Web前端開發(fā)之Javascript視頻》的課件,請配合大師哥《Javascript》視頻課程學(xué)習(xí)。
表單校驗(yàn)可以確保用戶以正確的格式填寫表單數(shù)據(jù),確保提交的數(shù)據(jù)能使應(yīng)用程序正常工作;
當(dāng)輸入數(shù)據(jù)時(shí),Web應(yīng)用會(huì)驗(yàn)證輸入的數(shù)據(jù)是否是正確;如果驗(yàn)證通過,應(yīng)用允許提交這些數(shù)據(jù)到服務(wù)器端并儲(chǔ)存到數(shù)據(jù)庫中,如果驗(yàn)證未通過,則應(yīng)用會(huì)提示有錯(cuò)誤的數(shù)據(jù),并且一般都會(huì)明確的提示錯(cuò)誤發(fā)生在哪里;
表單的數(shù)據(jù)校驗(yàn)的作用:
希望以正確的格式獲取到正確的數(shù)據(jù):如果用戶的數(shù)據(jù)以不正確的格式存儲(chǔ),或者沒有輸入正確的信息或都沒有輸入信息,Web應(yīng)用程序?qū)o法正常運(yùn)行;
保護(hù)用戶的信息安全:強(qiáng)制用戶輸入安全的密碼,有利于保護(hù)他們的賬戶信息;
保障網(wǎng)站的安全:惡意用戶有很多通過濫用應(yīng)用中缺乏保護(hù)的表單破壞應(yīng)用的方法;
表單數(shù)據(jù)校驗(yàn)的方式:
表單校驗(yàn)可以通過許多不同的方式實(shí)現(xiàn),主要是兩端校驗(yàn);
客戶端校驗(yàn):
發(fā)生在瀏覽器端,表單數(shù)據(jù)被提交到服務(wù)器之前,這種方式相較于服務(wù)器端校驗(yàn)來說,用戶體驗(yàn)更好,它能實(shí)時(shí)的反饋用戶的輸入校驗(yàn)結(jié)果,這種類型的校驗(yàn)可以進(jìn)一步細(xì)分以下方式:
JavaScript校驗(yàn):利用Javascript,可以完全自定義校驗(yàn)表單數(shù)據(jù)的實(shí)現(xiàn)方式;
HTML5約束校驗(yàn):也就是HTML5內(nèi)置的校驗(yàn),其不需要JavaScript,而且性能更好,但是不如JavaScript校驗(yàn)?zāi)菢涌梢宰远x,靈活性不夠;
服務(wù)器端校驗(yàn):
發(fā)生在瀏覽器提交數(shù)據(jù)并被服務(wù)器端接收之后;通常服務(wù)器端校驗(yàn)都是發(fā)生在將數(shù)據(jù)寫入數(shù)據(jù)庫之前,如果數(shù)據(jù)沒通過校驗(yàn),則會(huì)直接從服務(wù)器端返回錯(cuò)誤消息,并且告訴瀏覽器端發(fā)生錯(cuò)誤的具體位置和原因;
服務(wù)器端校驗(yàn)的缺點(diǎn)是,不像客戶端校驗(yàn)?zāi)菢佑斜容^好的用戶體驗(yàn),因?yàn)樗钡秸麄€(gè)表單都提交后才能返回錯(cuò)誤信息;
服務(wù)器端校驗(yàn)是Web應(yīng)用對抗錯(cuò)誤或惡意數(shù)據(jù)的最后防線,在這之后,數(shù)據(jù)將被持久化至數(shù)據(jù)庫;如今所有的服務(wù)端框架都提供了數(shù)據(jù)校驗(yàn)與安全功能;
在真實(shí)的項(xiàng)目開發(fā)過程中,幾乎同時(shí)使用客戶端校驗(yàn)與服務(wù)器端校驗(yàn)的組合校驗(yàn)方式,以確保數(shù)據(jù)的正確性與安全性,即兩端校驗(yàn)
HTML5約束驗(yàn)證API:
也稱為內(nèi)置表單驗(yàn)證;為了在表單提交到服務(wù)器之前驗(yàn)證數(shù)據(jù),HTML5為控件新增了一些約束驗(yàn)證的功能,有了這些功能,即使Javascript被禁用或由于種種原因未能加載,也可以確保基本的驗(yàn)證,但低版本的瀏覽器不支持或部分支持;
在表單提交時(shí),如果表單元素未通過約束驗(yàn)證,瀏覽器將在第一個(gè)無效表單元素上顯示錯(cuò)誤消息,并且可以根據(jù)錯(cuò)誤類型顯示默認(rèn)消息或自定義設(shè)置的消息;
約束屬性:
required屬性:必填,任何標(biāo)有required屬性的表單元素,在提交表單時(shí)都不能為空,其適用于<input>、<textarea>和<select>等元素;如:
<input type="text" name="username" required />
在Javascript中,使用對應(yīng)的required屬性,如:
// 檢測瀏覽器是否支持required屬性
var isRequiredSupported = "required" in document.createElement("input");
// 檢測required屬性
var isUsernameRequired = document.forms[0].elements["username"].required;
如果輸入一個(gè)空格,可以通過約束,像這種情況我們是不希望看到的,也是必須要避免的,所以此時(shí)還是需要Javascript來進(jìn)行驗(yàn)證,如:
document.forms[0].addEventListener("submit", function(event){
var textbox = document.forms[0].elements[0];
if(textbox.value.trim() == ""){
console.log("不能為空");
event.preventDefault();
}
});
限制輸入的長度:
所有文本框都可以使用minlength和maxlength屬性來限制長度;如果輸入的字段長度小于minlength的值或大于maxlength值則無效;Javascript可以使用minLength和maxLength屬性來訪問;如:
<input type="text" id="username" name="username" required minlength="4" maxlength="6" />
<script>
var username = document.forms[0].elements["username"];
console.log(username.minLength, username.maxLength);
</script>
type屬性:增加了幾種類型,這些新類型不僅能反映數(shù)據(jù)類型的信息,而且還能提供一些默認(rèn)的驗(yàn)證功能;其中,”email”和”url”是得到支持最多的類型,如:
<input type="email" name="email" />
<input type="url" name="homepage" />
要檢測瀏覽器是否支持這些新類型,可以在Javascript創(chuàng)建一個(gè)<input>元素,然后將type屬性設(shè)置為”email”或”url”,最后再檢測這個(gè)屬性值,對于不支持它們的瀏覽器會(huì)自動(dòng)將未知的值設(shè)置為“text”,而支持的瀏覽器則會(huì)返回正確的值,如:
var input = document.createElement("input");
input.type = "email";
var isEmailSupported = (input.type == "email");
存在一個(gè)問題,“-@-”會(huì)被當(dāng)成一個(gè)有效的郵件地址,這顯然有點(diǎn)不合理;
document.forms[0].addEventListener("submit", function(event){
var email = document.forms[0].elements["email"];
if(email.value != ""){
// 中文正則
// ^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$
var pattern = /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/;
if(!pattern.test(email.value)){
console.log("請正確輸入郵箱");
event.preventDefault();
}
}
});
如果不為新類型的<input>設(shè)置required屬性,那么空文本框也會(huì)驗(yàn)證通過;另外,設(shè)置特定的輸入類型并不能阻止用戶輸入無效的值,只是應(yīng)用某些默認(rèn)的驗(yàn)證而已;
type為”tel”的元素:
"tel" 類型的元素用于讓用戶輸入和編輯電話號(hào)碼,但瀏覽器不會(huì)自動(dòng)驗(yàn)證它的格式,因?yàn)槭澜绺鞯氐碾娫捥?hào)碼格式差別很大,所以其在功能、表現(xiàn)上與“text”一致;
<input id="tel" name="tel" type="tel" required />
即使如此,但其在移動(dòng)端,可能會(huì)提供為輸入電話號(hào)碼而優(yōu)化的自定義鍵盤;另外,使用電話號(hào)碼的特定輸入類型也使添加自定義驗(yàn)證和處理電話號(hào)碼更方便;例如,要求電話必填,用到了required屬性,并且格式是中國的手機(jī)號(hào)碼格式,如:
document.forms[0].addEventListener("submit", function(event){
var tel = document.forms[0].elements["tel"];
// 固話 :(\(\d{3,4}\)|\d{3,4}-|\s)?\d{8}
var telPattern = /^(\(\d{3,4}\)|\d{3,4}-|\s)?\d{8}$/;
if(!telPattern.test(tel.value)){
console.log("電話號(hào)碼不正確");
event.preventDefault();
}
});
處理國際電話號(hào)碼的方案,如:
<form>
<p>
<label for="country">選擇國家:</label>
<select id="country" name="country">
<option value="CN" selected>中國</option>
<option value="UK">英國</option>
<option value="US">美國</option>
<option value="GER">德國</option>
</select>
</p>
<p>
<label>輸入電話號(hào)碼: </label>
<input id="areaNo" name="areaNo" type="tel" required
placeholder="區(qū)號(hào)" pattern="[0-9]{3,4}" />
<input id="number1" name="number1" type="tel" required
placeholder="號(hào)碼" pattern="[0-9]{7,8}" />
<input id="number2" name="number2" type="tel"
placeholder="分機(jī)" pattern="[0-9]*" />
</p>
<p><button>提交</button></p>
</form>
<script>
var selectElem = document.querySelector("select");
var inputElems = document.querySelectorAll("input");
selectElem.onchange = function() {
for(var i = 0; i < inputElems.length; i++) {
inputElems[i].value = "";
}
if(selectElem.value === "CN"){
inputElems[2].parentNode.style.display = "inline";
inputElems[0].placeholder = "區(qū)號(hào)";
inputElems[0].pattern = "[0-9]{4}";
inputElems[1].placeholder = "號(hào)碼";
inputElems[1].pattern = "[0-9]{7,8}";
inputElems[2].required = false;
inputElems[2].placeholder = "分機(jī)";
inputElems[2].pattern = "[0-9]*";
}else if(selectElem.value === "US") {
inputElems[2].parentNode.style.display = "inline";
inputElems[0].placeholder = "Area code";
inputElems[0].pattern = "[0-9]{3}";
inputElems[1].placeholder = "First part";
inputElems[1].pattern = "[0-9]{3}";
inputElems[2].required = true;
inputElems[2].placeholder = "Second part";
inputElems[2].pattern = "[0-9]{4}";
} else if(selectElem.value === "UK") {
inputElems[2].parentNode.style.display = "none";
inputElems[0].placeholder = "Area code";
inputElems[0].pattern = "[0-9]{3,6}";
inputElems[1].placeholder = "Local number";
inputElems[1].pattern = "[0-9]{4,8}";
} else if(selectElem.value === "Ger") {
inputElems[2].parentNode.style.display = "inline";
inputElems[2].required = true;
inputElems[0].placeholder = "Area code";
inputElems[0].pattern = "[0-9]{3,5}";
inputElems[1].placeholder = "First part";
inputElems[1].pattern = "[0-9]{2,4}";
inputElems[2].placeholder = "Second part";
inputElems[2].pattern = "[0-9]{4}";
}
}
</script>
type為“search”的元素,與“text”功能和表現(xiàn)基本一致,只不過其右則有個(gè)刪除號(hào)(X),所以在實(shí)際應(yīng)用中,可以把它當(dāng)作“text”一樣使用;
type為”color”的元素,除了IE,其他瀏覽器都支持,其調(diào)用的是系統(tǒng)的調(diào)色板,并且并沒有提供類型的約束驗(yàn)證;
<input type="color" id="color" name="color" value="#FF0000" />
需要注意的是,其value值必須加“#”號(hào)的16進(jìn)制,且完整,如“#ff0000”,也不能使用關(guān)鍵字,如“red”,并且不能調(diào)節(jié)Alpha通道;
var color = document.forms[0].elements["color"];
color.addEventListener("change", function(event){
document.body.style.backgroundColor = event.target.value;
});
各瀏覽器呈現(xiàn)的樣式有可能不一致,可以統(tǒng)一采用按鈕代替,如:
<input type="color" id="color" name="color" style="display: none;" />
<input type="button" id="btnColor" name="btnColor" value="調(diào)色板" />
<input type="text" id="txtColor" name="txtColor" placeholder="#FFFFFF" />
<script>
var btnColor = document.getElementById("btnColor");
btnColor.addEventListener("click", function(event){
var color = document.getElementById("color");
color.click();
color.addEventListener("change", function(event){
document.getElementById("txtColor").value = this.value;
});
},false);
</script>
數(shù)值范圍:
HTML5還定義了其他幾個(gè)輸入元素,這些元素都要求填寫某種基于數(shù)字的值,如:”number”、”range”、”datetime”、”datetime-local”、”date”、”month”、”week”和”time”;瀏覽器對這些類型的支持并不友好;
對于所有這些數(shù)值類型的輸入元素,可以指定min、max和step屬性(步長值或差值),如:
<input type="number" min="20" max="100" step="5" name="age" />
檢測瀏覽器是否支持,方法同上;
在Javascript中,以上屬性都有相對應(yīng)的同名屬性,另外,還存在兩個(gè)方法:stepUp()和stepDown(),都接收一個(gè)可選的參數(shù):在當(dāng)前值的基礎(chǔ)上加上或減去的step倍數(shù)的數(shù)值(默認(rèn)加減1),如:
var age = document.forms[0].elements["age"];
age.stepUp(); // 增加5,因?yàn)閟tep為5
age.stepUp(10); // 增加50,為step的10倍
age.stepDown(); // 減少5
age.stepDown(3); // 減少step的3倍,15
IE在輸入非數(shù)字的情況下也可以通過約束,因此,需要使用Javascript判斷驗(yàn)證,如:
var age = document.forms[0].elements["age"];
age.addEventListener("keypress", function(event){
var charCode = event.charCode;
if(!/\d/.test(String.fromCharCode(charCode)))
event.preventDefault();
});
type為range的元素,IE9不支持,并且在各瀏覽器中呈現(xiàn)的樣式并不一致;
<input type="range" max="50" min="10" step="2" value="30" />
其擁有屬性:
var range = document.querySelector('input[type="range"]');
console.log(range.max);
console.log(range.min);
console.log(range.step);
console.log(range.value);
console.log(range.defaultValue);
type為”date”、”datetime”、”datetime-local”、”month”、”week”和”time”,IE不支持,所有瀏覽器不支持”datetime”,F(xiàn)irefox只支持”date”和”time”;各瀏覽器呈現(xiàn)的也不一致;所以目前在所有應(yīng)用中,并不會(huì)使用這些表單元素;對于不支持的表單元素,瀏覽器直接解析為type為“text”元素;
pattern屬性:輸入模式
該屬性也是HTML5新增的,其值是一個(gè)正則表達(dá)式,用于匹配文本框中的值;、
<input type="text" name="age" pattern="\d+" />
<!-- 限制為4-8個(gè)字符,并要求它只包含小寫字母 -->
<input type="text" id="username" name="username" pattern="[a-z]{4,8}" required />
<!-- 包含大小寫字母和數(shù)字的組合,長度在8-10之間 -->
<input type="password" id="pwd" name="pwd" pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}" />
注,模式的開頭和末尾不用加^和$;
在Javascript中,通過同名的pattern屬性來訪問模式,如:
var pattern = document.forms[0].elements[0].pattern;
// 檢測是否支持
var isPatternSupported = "pattern" in document.createElement("input");
// 身份證號(hào)
var id = document.getElementById("id");
id.pattern = "([0-9]){17}(\\d|x|X)";
注:<textarea>不支持pattern屬性;
有一些<input>元素類型不需要pattern屬性進(jìn)行校驗(yàn),例如”email”和”url”類型,因?yàn)樗鼈儽旧砭途哂蓄愋透袷降男r?yàn);即使如此,也可以同時(shí)使用pattern屬性,可以更加詳細(xì)和靈活的定制約束規(guī)則;
檢測有效性:
使用表單元素的checkValidity()方法可以檢測該元素的值是否有效,如果其值有效,該方法返回true,否則返回false;
其判斷是否有效的依據(jù)就是以上所講的約束;如:
<input type="text" id="username" name="username" pattern="[a-z]{4,8}" required />
<p><input type="button" id="btn" name="btn" value="按鈕" /></p>
<script>
var btn = document.getElementById("btn");
btn.addEventListener("click", function(event){
var username = document.getElementById("username");
console.log(username.checkValidity());
if(username.checkValidity()){
console.log("約束通過");
}else{
console.log("不通過");
}
},false);
</script>
要檢測整個(gè)表單是否有效,可以在表單自身上調(diào)用checkValidity()方法;如果所有表單控件都有效,該方法返回true,即使其中一個(gè)表單無效,該方法都會(huì)返回false,如:
btn.addEventListener("click", function(event){
if(document.forms[0].checkValidity()){
console.log("約束通過");
}else{
console.log("不通過");
}
},false);
validity屬性:
checkValidity()方法只會(huì)返回是否有效的結(jié)果,但表單元素的validity屬性則會(huì)返回有效或無效的原因,該屬性是一個(gè)ValidityState類型的對象:
btn.onclick = function(){
var num = document.forms[0].elements["num"];
console.log(num.validity); // ValidityState
}
其包含一系列屬性,每個(gè)屬性會(huì)返回一個(gè)布爾值:
對于這些布爾屬性中的每一個(gè),值為true就表示驗(yàn)證失敗;如果出現(xiàn)失敗,瀏覽器將提醒用戶并阻止提交表單;如果驗(yàn)證成功,即其他屬性均返回false,則valid將為true,就可以提交表單;
因此,要想得到更具體的信息,就應(yīng)該使用validity屬性來檢測表單元素的有效性,如:
<p><input type="email" name="email" id="email" required pattern="[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+" maxlength="10" /></p>
<p><input type="button" id="btn" name="btn" value="按鈕" /></p>
</form>
<script>
var btn = document.getElementById("btn");
btn.addEventListener("click", function(event){
var email = document.getElementById("email");
if(email.validity && !email.validity.valid){
if(email.validity.valueMissing)
console.log("請輸入數(shù)據(jù)");
else if(email.validity.typeMismatch)
console.log("請輸入郵件地址");
else if(email.validity.tooLong)
console.log("超出長度");
else if(email.validity.patternMismatch)
console.log("地址中不能包括特殊字符");
else
console.log("啥玩意啊");
}
},false);
</script>
自定義錯(cuò)誤信息:
主要使用validationMessage屬性和setCustomValidity()方法;如果沒有通過驗(yàn)證,瀏覽器會(huì)有默認(rèn)地提示信息,該信息保存在表單元素的validationMessage屬性中,如:
var email = document.forms[0].elements["email"];
console.log(email.validationMessage); // 如果有required特性,提示"請?zhí)顚懘俗侄?#34;
var btn = document.getElementById("btn");
btn.addEventListener("click", function(event){
var email = document.getElementById("email");
// 根據(jù)不同的驗(yàn)證失敗的原因,提示各自默認(rèn)的信息
if(email.validity && !email.validity.valid){
if(email.validity.valueMissing)
console.log(email.validationMessage); // 請?zhí)顚懘俗侄? else if(email.validity.typeMismatch)
// 請?jiān)陔娮余]件地址中包括“@”。“a”中缺少“@”。
console.log(email.validationMessage);
else if(email.validity.tooLong)
console.log(email.validationMessage);
else if(email.validity.patternMismatch)
// 請與所請求的格式保持一致。
console.log(email.validationMessage);
else
console.log(email.validationMessage);
}
// 或者
// if(email.validity && !email.validity.valid){
// console.log(email.validationMessage);
// }
},false);
但是該屬性是只讀的,如果想修改這個(gè)值,可以調(diào)用setCustomValidity()改變validationMessage的值;如:
var email = document.forms[0].elements["email"];
email.setCustomValidity("不要懶,必須填!");
email.validationMessage = '這個(gè)字段必須填上。';
console.log(email.validationMessage);
現(xiàn)在再單擊提交,如果沒有驗(yàn)證通過,會(huì)提示自定義的消息;
如果將自定義錯(cuò)誤設(shè)置為truthy值,則將阻止提交表單;因?yàn)檎{(diào)用了setCustomValidity()方法,所以validity的customError屬性為true,導(dǎo)致validy屬性為false,所以提交不了;
var btnsubmit = document.querySelector('input[type="submit"]');
btnsubmit.addEventListener("click", function(event){
console.log(email.validationMessage);
console.log(email.checkValidity()); // false
// customError: true, valueMissing: true, valid: false
console.log(email.validity);
});
只有將自定義消息設(shè)置為空才能提交表單,而將自定義消息設(shè)置為空,也就是將消息恢復(fù)為瀏覽器默認(rèn)的消息,如:
btnsubmit.addEventListener("click", function(event){
if (email.value != "") {
email.setCustomValidity("");
}
console.log(email.validationMessage); // 默認(rèn)的消息,地址包含@
console.log(email.checkValidity()); // false
// typeMismatch:true, valid: false
console.log(email.validity);
});
如果此時(shí)沒有下一個(gè)約束,或者其他驗(yàn)證均有效的話,就可以順利得交了;
當(dāng)然,這些代碼放到一個(gè)普通按鈕的click事件處理程序中也是可以的,如:
var btn = document.getElementById("btn");
btn.addEventListener("click", function(event){
if (email.value != "") {
email.setCustomValidity("");
}
console.log(email.validationMessage);
console.log(email.checkValidity());
console.log(email.validity);
if (!email.checkValidity()) {
console.log(email.validationMessage);
}else{
document.forms[0].submit();
}
});
可以根據(jù)不同的約束驗(yàn)證失敗時(shí)分別自定義提示消息,如:
function validate(input) {
var validityState = input.validity;
if(validityState.valueMissing){
input.setCustomValidity('必填');
}else if(validityState.typeMismatch){
input.setCustomValidity('類型不正確');
}else if(validityState.rangeUnderflow) {
input.setCustomValidity('值太小');
}else if(validityState.rangeOverflow) {
input.setCustomValidity('值太大');
}else if(validityState.stepMisMatch){
input.setCustomValidity('步長值不合理');
}else if(validityState.tooLong){
input.setCustomValidity('長度超出了maxLength');
}else if(validityState.tooShort){
input.setCustomValidity('長度小于minLength');
}else if(validityState.patternMismatch){
input.setCustomValidity("格式不正確");
}else if(validityState.badInput){
input.setCustomValidity('值類型無法轉(zhuǎn)換');
} else {
input.setCustomValidity('');
}
return validityState.valid;
}
// 應(yīng)用
var btnsubmit = document.querySelector('input[type="submit"]');
btnsubmit.addEventListener("click", function(event){
var email = document.getElementById("email");
if(!validate(email)){
console.log(email.validationMessage);
console.log(email.checkValidity());
console.log(email.validity);
}
});
// 或者普通按鈕
var btn = document.getElementById("btn");
btn.addEventListener("click", function(event){
var email = document.getElementById("email");
if(!validate(email)){
console.log(email.validationMessage);
console.log(email.checkValidity());
console.log(email.validity);
}else{
document.forms[0].submit();
}
});
也可以配合正則表達(dá)式,設(shè)備自定義錯(cuò)誤消息,如:
<form>
<label for="ZIP">郵編:</label>
<input type="text" id="ZIP">
<label for="Country">國家:</label>
<select id="Country">
<option value="cn">中國</option>
<option value="ch">瑞士</option>
<option value="fr">法國</option>
<option value="de">德國</option>
<option value="nl">荷蘭</option>
</select>
<input type="submit" value="Validate">
</form>
<script>
function checkZIP() {
// 定義每個(gè)國家對應(yīng)的,郵政編碼必須遵循的模式及消息
var constraints = {
cn : [ '^(CN-)?\\d{5}$', "中國郵編需要5個(gè)數(shù)字:例如CN-10022或10022"],
ch : [ '^(CH-)?\\d{4}$', "瑞士郵編需要4個(gè)數(shù)字:例如CH-1950或1950" ],
fr : [ '^(F-)?\\d{5}$' , "法國郵編需要5個(gè)數(shù)字:例如F-75012或75012" ],
de : [ '^(D-)?\\d{5}$' , "德國郵編需要5個(gè)數(shù)字:例如D-12345或12345" ],
nl : [ '^(NL-)?\\d{4}\\s*([A-RT-Z][A-Z]|S[BCE-RT-Z])$',
"荷蘭郵編需要4位數(shù)字,后跟除SA、SD和SS之外的2個(gè)字母" ]
};
var country = document.getElementById("Country").value;
var ZIPField = document.getElementById("ZIP");
// 創(chuàng)建正則對象
var constraint = new RegExp(constraints[country][0], "");
console.log(constraint);
// 檢測
if(constraint.test(ZIPField.value)) {
// 通過約束校驗(yàn)
ZIPField.setCustomValidity("");
}else{
// 沒有通過約束校驗(yàn),設(shè)置當(dāng)前國家的錯(cuò)誤消息
ZIPField.setCustomValidity(constraints[country][1]);
}
}
window.onload = function () {
document.getElementById("Country").onchange = checkZIP;
document.getElementById("ZIP").oninput = checkZIP;
}
</script>
novalidate屬性和formnovalidate屬性:
禁用驗(yàn)證,可以設(shè)置表單不進(jìn)行驗(yàn)證;
<form name="myform" novalidate ></form>
在Javascript中使用noValidate屬性可以獲取或設(shè)置這個(gè)值,如果這個(gè)屬性存在,值為true,否則為false;
document.forms[0].noValidate = true; // 禁用驗(yàn)證
如果一個(gè)表單中有多個(gè)提交按鈕,為了指定點(diǎn)擊某個(gè)提交按鈕不必驗(yàn)證表單,可以在相應(yīng)的按鈕上添加formnovalidate屬性,如:
<form name="myform">
<input type="submit" value="驗(yàn)證提交" />
<input type="submit" formnovalidate value="不驗(yàn)證提交" />
</form>
使用Javascript也可以設(shè)置這個(gè)屬性:
document.forms[0].elements["btnNoValidate"].formNoValidate = true;
一般情況下,表單使用novalidate屬性關(guān)閉瀏覽器的自動(dòng)校驗(yàn)的目的,就是使用腳本控制表單的校驗(yàn);但是,這并不會(huì)禁止對約束校驗(yàn)的支持或?qū)s束CSS偽類的支持;如:
<style>
input:invalid{border-color: #900; background-color: #FDD;}
input:focus:invalid{outline: none;}
.error {color: white; background-color: lightgreen; padding: 0.1em 0.2em;}
.error.active {background-color: red;}
</style>
<form novalidate>
<p>郵箱地址:<input type="email" id="mail" name="mail" required />
<span class="error">如:a@a.com</span></p>
<button>提交</button>
</form>
<script>
var form = document.getElementsByTagName('form')[0];
var email = document.getElementById('mail');
var error = document.querySelector('.error');
email.addEventListener("input", function (event) {
if (email.validity.valid) {
error.innerHTML = "正確";
error.className = "error";
}
}, false);
form.addEventListener("submit", function (event) {
if(!email.validity.valid){
error.innerHTML = "期望一個(gè)正確郵箱地址";
error.className = "error active";
event.preventDefault();
}
}, false);
</script>
invalid事件:
當(dāng)表單提交時(shí),若任一個(gè)表單元素在檢查有效性時(shí),不符合對它的約束條件,則會(huì)觸發(fā)invalid事件;對元素有效性的檢查是在提交表單之前或調(diào)用表單或表單元素自己的checkValidity()方法之后;
<form>
輸入1-10之間的整數(shù):<input type="number" min="1" max="10" required /><br/>
<input type="submit" value="提交" />
<input type="button" id="btn" name="btn" value="按鈕" />
</form>
<p id="log">錯(cuò)誤:</p>
<script>
var input = document.querySelector('input[type="number"]');
var log = document.getElementById("log");
// 當(dāng)提交表單時(shí)觸發(fā)
input.addEventListener("invalid", function(event){
log.textContent += event.target.validationMessage;
});
// 調(diào)用checkValidity()也會(huì)觸發(fā)
var btn = document.getElementById("btn");
btn.addEventListener("click", function(event){
console.log(input.validity);
input.checkValidity(); // 觸發(fā)invalid事件
});
</script>
在也可以invalid事件中自定義錯(cuò)誤消息,如:
<form>
輸入大小寫字母:<input type="text" name="username" id="username" required pattern="[A-Za-z]+">
<input type="submit" value="提交" />
<input type="button" id="btn" name="btn" value="按鈕" />
</form>
<script>
var username = document.querySelector('#username');
username.addEventListener('input', function(e){
// 如果一開始沒有驗(yàn)證通過,必須在此設(shè)為空字符串,否則即使有效也無法提交
username.setCustomValidity('');
username.checkValidity();
});
// 提交時(shí)觸發(fā)
username.addEventListener('invalid', function(e){
// if(username.value === '') {
// username.setCustomValidity('請輸入用戶名');
// } else {
// username.setCustomValidity('用戶名只能包含大寫和小寫字母');
// }
// 或者
if(username.validity.valueMissing) {
username.setCustomValidity('請輸入用戶名');
}else if(username.validity.patternMismatch){
username.setCustomValidity('用戶名只能包含大寫和小寫字母');
}
});
// 調(diào)用checkValidity()觸發(fā)
var btn = document.getElementById("btn");
btn.addEventListener("click", function(event){
console.log(username.validity);
if(!username.checkValidity()){ // 觸發(fā)invalid事件
console.log(username.validationMessage);
}else{
document.forms[0].submit();
}
});
</script>
:valid和:invalid偽類:
:valid CSS偽類表示表單或表單元素?cái)?shù)據(jù)驗(yàn)證通過的樣式;
:invalid CSS偽類表示表單或表單元素未通過驗(yàn)證樣式;
這兩個(gè)偽類能簡單地將校驗(yàn)字段展示為一種能讓用戶辨別出其輸入數(shù)據(jù)的正確與否的樣式;
<style>
form:invalid {
border: 5px solid #ffdddd;
}
form:valid {
border: 5px solid #ddffdd;
}
input:valid {
background-color: powderblue;
}
input:invalid{
background-color: pink;
}
</style>
如:驗(yàn)證電話號(hào)碼:
<style>
div {margin-bottom: 10px; position: relative;}
input[type="tel"] {width: 100px;}
input + span {padding-right: 30px;}
input:invalid+span:after {
position: absolute; content: '?';
padding-left: 5px; color: #8b0000;
}
input:valid+span:after {
position: absolute;
content: '?'; padding-left: 5px; color: #009000;
}
</style>
<div>
<label for="tel">電話號(hào)碼(必填): </label>
<input id="tel" name="tel" type="tel" required>
<span class="validity"></span>
</div>
:required偽類和:optional偽類:
:required CSS偽類表示任意設(shè)置了required屬性的<input>、<select>或<textarea>元素;這個(gè)偽類對于高亮顯示在提交表單之前必須具有有效數(shù)據(jù)的字段非常有用;
:optional CSS偽類表示任意沒有required屬性的<input>、<select>或<textarea>元素使用它;
input:required{
border: 1px solid green;
}
input:optional {
border: 1px dashed black;
}
:in-range偽類和:out-of-range偽類:使用方式同上;
不使用內(nèi)置表單校驗(yàn)API:
對于老舊瀏覽器并不支持HTML的約束校驗(yàn),因此只能使用JavaScript來校驗(yàn)表單數(shù)據(jù),如:
<style>
input.invalid{border-color: #900; background-color: #FDD;}
input:focus.invalid{outline: none;}
.error {color: white; background-color: lightgreen; padding: 0.1em 0.2em;}
.error.active {background-color: red;}
</style>
<form>
<p>郵箱地址:<input type="text" class="mail" id="mail" name="mail">
<span class="error">如:a@a.com</span><p>
<button type="submit">提交</button>
</form>
<script>
var form = document.getElementsByTagName('form')[0];
var email = document.getElementById('mail');
var error = email;
while ((error = error.nextSibling).nodeType != 1);
var emailRegExp = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;
function addEvent(element, event, callback) {
element["on" + event] = function (e) {
var output = callback(e);
if (output === false)
return false;
};
};
addEvent(window, "load", function () {
var test = email.value.length === 0 || emailRegExp.test(email.value);
email.className = test ? "valid" : "invalid";
});
addEvent(email, "input", function () {
var test = email.value.length === 0 || emailRegExp.test(email.value);
if(test){
email.className = "valid";
error.innerHTML = "正確";
error.className = "error";
} else {
email.className = "invalid";
}
});
addEvent(form, "submit", function () {
var test = email.value.length !== 0 || emailRegExp.test(email.value);
console.log(test);
if(!test){
email.className = "invalid";
error.innerHTML = "需要一個(gè)正確的郵箱地址";
error.className = "error active";
return false;
}else{
email.className = "valid";
error.innerHTML = "正確";
error.className = "error";
}
});
</script>
遠(yuǎn)程校驗(yàn):
當(dāng)用戶輸入的數(shù)據(jù)與存儲(chǔ)在應(yīng)用程序服務(wù)器端的附加數(shù)據(jù)綁定時(shí),這種校驗(yàn)是必要的,一般采用Ajax異步請求進(jìn)行校驗(yàn);
篇文篇主要簡述如何在springboot中驗(yàn)證表單信息。在springmvc工程中,需要檢查表單信息,表單信息驗(yàn)證主要通過注解的形式。
構(gòu)建工程
創(chuàng)建一個(gè)springboot工程,由于用到了 web 、thymeleaf、validator、el,引入相應(yīng)的起步依賴和依賴,代碼清單如下:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-el</artifactId>
</dependency>
</dependencies>
創(chuàng)建一個(gè)PresonForm的Object類
package com.forezp.entity; import javax.validation.constraints.Min; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; /** * Created by fangzhipeng on 2017/4/19. */ public class PersonForm { @NotNull @Size(min=2, max=30) private String name; @NotNull @Min(18) private Integer age; public String getName() { return this.name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String toString() { return "Person(Name: " + this.name + ", Age: " + this.age + ")"; } }
這個(gè)實(shí)體類,在2個(gè)屬性:name,age.它們各自有驗(yàn)證的注解:
創(chuàng)建 web Controller
@Controller public class WebController extends WebMvcConfigurerAdapter { @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/results").setViewName("results"); } @GetMapping("/") public String showForm(PersonForm personForm) { return "form"; } @PostMapping("/") public String checkPersonInfo(@Valid PersonForm personForm, BindingResult bindingResult) { if (bindingResult.hasErrors()) { return "form"; } return "redirect:/results"; } }
創(chuàng)建form表單
src/main/resources/templates/form.html:
<html>
<body>
<form action="#" th:action="@{/}" th:object="${personForm}" method="post">
<table>
<tr>
<td>Name:</td>
<td><input type="text" th:field="*{name}" /></td>
<td th:if="${#fields.hasErrors('name')}" th:errors="*{name}">Name Error</td>
</tr>
<tr>
<td>Age:</td>
<td><input type="text" th:field="*{age}" /></td>
<td th:if="${#fields.hasErrors('age')}" th:errors="*{age}">Age Error</td>
</tr>
<tr>
<td><button type="submit">Submit</button></td>
</tr>
</table>
</form>
</body>
</html>
注冊成功的頁面
src/main/resources/templates/results.html:
<html>
<body>
Congratulations! You are old enough to sign up for this site.
</body>
</html>
演示
啟動(dòng)工程,訪問http://localhost:8080/:
如果你輸入A和15,點(diǎn)擊 submit:
如果name 輸入N, age為空:
如果輸入:forezp. 18
參考資料
https://spring.io/guides/gs/validating-form-input/
MValidator是一個(gè)易用、輕量且強(qiáng)大的表單驗(yàn)證工具。支持html和javascript兩種配置方式,可以立即或手動(dòng)觸發(fā)驗(yàn)證,獨(dú)立顯示每條規(guī)則的信息,可自定義表單或信息容器的樣式。目前minify文件還不到5KB,而且不依賴任何第三方庫。
使用方法:
1. 給input指定驗(yàn)證規(guī)則
<!--使用data-rule屬性指定驗(yàn)證規(guī)則--> <input type="text" data-rule="required">
或者使用js配置
//fields字段與input的name對應(yīng),指定這個(gè)input的驗(yàn)證規(guī)則 //<input type="text" name="field1"> new SMValidator('form', { fields:{ field1: 'required' } });
2. 綁定需要驗(yàn)證的表單
selector是css選擇器,內(nèi)部使用document.querySelectorAll解析,你可以使用瀏覽器支持的任何css選擇器規(guī)則。SMValidator從選擇結(jié)果中篩選出指定的input進(jìn)行綁定,并在適當(dāng)?shù)臅r(shí)機(jī)較驗(yàn)其value是否符合要求。
其他詳細(xì)的功能請到移步到github上查看文檔和demo源碼,可以實(shí)現(xiàn)很多自定義效果
*請認(rèn)真填寫需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。