本内容是《Web前端开发之Javascript视频》的课件,请配合大师哥《Javascript》视频课程学习。
表单校验可以确保用户以正确的格式填写表单数据,确保提交的数据能使应用程序正常工作;当输入数据时,Web应用会验证输入的数据是否是正确;如果验证通过,应用允许提交这些数据到服务器端并储存到数据库中,如果验证未通过,则应用会提示有错误的数据,并且一般都会明确的提示错误发生在哪里;
表单的数据校验的作用:希望以正确的格式获取到正确的数据:如果用户的数据以不正确的格式存储,或者没有输入正确的信息或都没有输入信息,Web应用程序将无法正常运行;保护用户的信息安全:强制用户输入安全的密码,有利于保护他们的账户信息;保障网站的安全:恶意用户有很多通过滥用应用中缺乏保护的表单破坏应用的方法;
表单数据校验的方式:表单校验可以通过许多不同的方式实现,主要是两端校验;
客户端校验:发生在浏览器端,表单数据被提交到服务器之前,这种方式相较于服务器端校验来说,用户体验更好,它能实时的反馈用户的输入校验结果,这种类型的校验可以进一步细分以下方式:JavaScript校验:利用Javascript,可以完全自定义校验表单数据的实现方式;HTML5约束校验:也就是HTML5内置的校验,其不需要JavaScript,而且性能更好,但是不如JavaScript校验那样可以自定义,灵活性不够;
服务器端校验:发生在浏览器提交数据并被服务器端接收之后;通常服务器端校验都是发生在将数据写入数据库之前,如果数据没通过校验,则会直接从服务器端返回错误消息,并且告诉浏览器端发生错误的具体位置和原因;服务器端校验的缺点是,不像客户端校验那样有比较好的用户体验,因为它直到整个表单都提交后才能返回错误信息;服务器端校验是Web应用对抗错误或恶意数据的最后防线,在这之后,数据将被持久化至数据库;如今所有的服务端框架都提供了数据校验与安全功能;在真实的项目开发过程中,几乎同时使用客户端校验与服务器端校验的组合校验方式,以确保数据的正确性与安全性,即两端校验
HTML5约束验证API:
也称为内置表单验证;为了在表单提交到服务器之前验证数据,HTML5为控件新增了一些约束验证的功能,有了这些功能,即使Javascript被禁用或由于种种原因未能加载,也可以确保基本的验证,但低版本的浏览器不支持或部分支持;
在表单提交时,如果表单元素未通过约束验证,浏览器将在第一个无效表单元素上显示错误消息,并且可以根据错误类型显示默认消息或自定义设置的消息;
约束属性:quid属性:必填,任何标有quid属性的表单元素,在提交表单时都不能为空,其适用于input、textaa和select等元素;如:
inputtype="text"name="username"quid/在Javascript中,使用对应的quid属性,如://检测浏览器是否支持quid属性varisRequidSupported="quid"indocument.cateElement("input");//检测quid属性varisUsernameRequid=document.forms[0].elements["username"].quid;
如果输入一个空格,可以通过约束,像这种情况我们是不希望看到的,也是必须要避免的,所以此时还是需要Javascript来进行验证,如:
document.forms[0].addEventListener("submit",function(event){vartextbox=document.forms[0].elements[0];if(textbox.value.trim()==""){console.log("不能为空");event.pventDefault();}});
限制输入的长度:所有文本框都可以使用minlength和maxlength属性来限制长度;如果输入的字段长度小于minlength的值或大于maxlength值则无效;Javascript可以使用minLength和maxLength属性来访问;如:
inputtype="text"id="username"name="username"quidminlength="4"maxlength="6"/scriptvarusername=document.forms[0].elements["username"];console.log(username.minLength,username.maxLength);/script
type属性:增加了几种类型,这些新类型不仅能反映数据类型的信息,而且还能提供一些默认的验证功能;其中,”email”和”url”是得到支持最多的类型,如:
inputtype="email"name="email"/inputtype="url"name="homepage"/
要检测浏览器是否支持这些新类型,可以在Javascript创建一个input元素,然后将type属性设置为”email”或”url”,最后再检测这个属性值,对于不支持它们的浏览器会自动将未知的值设置为“text”,而支持的浏览器则会返回正确的值,如:
varinput=document.cateElement("input");input.type="email";varisEmailSupported=(input.type=="email");
存在一个问题,“-
-”会被当成一个有效的邮件地址,这显然有点不合理;
document.forms[0].addEventListener("submit",function(event){varemail=document.forms[0].elements["email"];if(email.value!=""){//中文正则//^[A-Za-z0-9\u4e00-\u9fa5]+
[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$varpattern=/^[a-zA-Z0-9_-]+[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/;if(!pattern.test(email.value)){console.log("请正确输入邮箱");event.pventDefault();}}});
如果不为新类型的input设置quid属性,那么空文本框也会验证通过;另外,设置特定的输入类型并不能阻止用户输入无效的值,只是应用某些默认的验证而已;
type为”tel”的元素:"tel"类型的元素用于让用户输入和编辑电话号码,但浏览器不会自动验证它的格式,因为世界各地的电话号码格式差别很大,所以其在功能、表现上与“text”一致;
inputid="tel"name="tel"type="tel"quid/
即使如此,但其在移动端,可能会提供为输入电话号码而优化的自定义键盘;另外,使用电话号码的特定输入类型也使添加自定义验证和处理电话号码更方便;例如,要求电话必填,用到了quid属性,并且格式是中国的手机号码格式,如:
document.forms[0].addEventListener("submit",function(event){vartel=document.forms[0].elements["tel"];//固话
\(\d{3,4}\)
\d{3,4}-
\s)?\d{8}vartelPattern=/^(\(\d{3,4}\)
\d{3,4}-
\s)?\d{8}$/;if(!telPattern.test(tel.value)){console.log("电话号码不正确");event.pventDefault();}});
处理国际电话号码的方案,如:
formplabelfor="country"选择国家:/labelselectid="country"name="country"optionvalue="CN"selected中国/optionoptionvalue="UK"英国/optionoptionvalue="US"美国/optionoptionvalue="GER"德国/option/select/pplabel输入/labelinputid="aaNo"name="aaNo"type="tel"quidplaceholder="区号"pattern="[0-9]{3,4}"/inputid="number1"name="number1"type="tel"quidplaceholder="号码"pattern="[0-9]{7,8}"/inputid="number2"name="number2"type="tel"placeholder="分机"pattern="[0-9]*"//ppbutton提交/button/p/formscriptvarselectElem=document.querySelector("select");varinputElems=document.querySelectorAll("input");selectElem.onchange=function(){for(vari=0;iinputElems.length;i++){inputElems.value="";}if(selectElem.value==="CN"){inputElems[2].pantNode.style.display="inline";inputElems[0].placeholder="区号";inputElems[0].pattern="[0-9]{4}";inputElems[1].placeholder="号码";inputElems[1].pattern="[0-9]{7,8}";inputElems[2].quid=false;inputElems[2].placeholder="分机";inputElems[2].pattern="[0-9]*";}elseif(selectElem.value==="US"){inputElems[2].pantNode.style.display="inline";inputElems[0].placeholder="Aacode";inputElems[0].pattern="[0-9]{3}";inputElems[1].placeholder="Firstpart";inputElems[1].pattern="[0-9]{3}";inputElems[2].quid=true;inputElems[2].placeholder="Secondpart";inputElems[2].pattern="[0-9]{4}";}elseif(selectElem.value==="UK"){inputElems[2].pantNode.style.display="none";inputElems[0].placeholder="Aacode";inputElems[0].pattern="[0-9]{3,6}";inputElems[1].placeholder="Localnumber";inputElems[1].pattern="[0-9]{4,8}";}elseif(selectElem.value==="Ger"){inputElems[2].pantNode.style.display="inline";inputElems[2].quid=true;inputElems[0].placeholder="Aacode";inputElems[0].pattern="[0-9]{3,5}";inputElems[1].placeholder="Firstpart";inputElems[1].pattern="[0-9]{2,4}";inputElems[2].placeholder="Secondpart";inputElems[2].pattern="[0-9]{4}";}}/script
type为“search”的元素,与“text”功能和表现基本一致,只不过其右则有个删除号(X),所以在实际应用中,可以把它当作“text”一样使用;
type为”color”的元素,除了IE,其他浏览器都支持,其调用的是系统的调色板,并且并没有提供类型的约束验证;
inputtype="color"id="color"name="color"value="#FF"/
需要注意的是,其value值必须加“#”号的16进制,且完整,如“#ff”,也不能使用关键字,如“d”,并且不能调节Alpha通道;
varcolor=document.forms[0].elements["color"];color.addEventListener("change",function(event){document.body.style.backgroundColor=event.target.value;});
各浏览器呈现的样式有可能不一致,可以统一采用按钮代替,如:
inputtype="color"id="color"name="color"style="display:none;"/inputtype="button"id="btnColor"name="btnColor"value="调色板"/inputtype="text"id="txtColor"name="txtColor"placeholder="#FFFFFF"/scriptvarbtnColor=document.getElementById("btnColor");btnColor.addEventListener("click",function(event){varcolor=document.getElementById("color");color.click();color.addEventListener("change",function(event){document.getElementById("txtColor").value=this.value;});},false);/script
数值范围:HTML5还定义了其他几个输入元素,这些元素都要求填写某种基于数字的值,如:”number”、”range”、”datetime”、”datetime-local”、”date”、”month”、”week”和”time”;浏览器对这些类型的支持并不友好;对于所有这些数值类型的输入元素,可以指定min、max和step属性(步长值或差值),如:
inputtype="number"min="20"max=""step="5"name="age"/
检测浏览器是否支持,方法同上;
在Javascript中,以上属性都有相对应的同名属性,另外,还存在两个方法:stepUp()和stepDown(),都接收一个可选的参数:在当前值的基础上加上或减去的step倍数的数值(默认加减1),如:
varage=document.forms[0].elements["age"];age.stepUp();//增加5,因为step为5age.stepUp(10);//增加50,为step的10倍age.stepDown();//减少5age.stepDown(3);//减少step的3倍,15
IE在输入非数字的情况下也可以通过约束,因此,需要使用Javascript判断验证,如:
varage=document.forms[0].elements["age"];age.addEventListener("keypss",function(event){varcharCode=event.charCode;if(!/\d/.test(String.fromCharCode(charCode)))event.pventDefault();});
type为range的元素,IE9不支持,并且在各浏览器中呈现的样式并不一致;
inputtype="range"max="50"min="10"step="2"value="30"/
其拥有属性:
max:设置或返回滑块控件的最大值;min:设置或返回滑块控件的最小值;step:设置或返回每次拖动滑块控件时的递增量;value:设置或返回滑块控件的value属性值;defaultValue:设置或返回滑块控件的默认值;
varrange=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”,Fifox只支持”date”和”time”;各浏览器呈现的也不一致;所以目前在所有应用中,并不会使用这些表单元素;对于不支持的表单元素,浏览器直接解析为type为“text”元素;
pattern属性:输入模式该属性也是HTML5新增的,其值是一个正则表达式,用于匹配文本框中的值;、
inputtype="text"name="age"pattern="\d+"/!--限制为4-8个字符,并要求它只包含小写字母--inputtype="text"id="username"name="username"pattern="[a-z]{4,8}"quid/!--包含大小写字母和数字的组合,长度在8-10之间--inputtype="password"id="pwd"name="pwd"pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}"/
注,模式的开头和末尾不用加^和$;
在Javascript中,通过同名的pattern属性来访问模式,如:
varpattern=document.forms[0].elements[0].pattern;//检测是否支持varisPatternSupported="pattern"indocument.cateElement("input");//身份证号varid=document.getElementById("id");id.pattern="([0-9]){17}(\\d
x
X)";
注:textaa不支持pattern属性;
有一些input元素类型不需要pattern属性进行校验,例如”email”和”url”类型,因为它们本身就具有类型格式的校验;即使如此,也可以同时使用pattern属性,可以更加详细和灵活的定制约束规则;
检测有效性:使用表单元素的checkValidity()方法可以检测该元素的值是否有效,如果其值有效,该方法返回true,否则返回false;其判断是否有效的依据就是以上所讲的约束;如:
inputtype="text"id="username"name="username"pattern="[a-z]{4,8}"quid/pinputtype="button"id="btn"name="btn"value="按钮"//pscriptvarbtn=document.getElementById("btn");btn.addEventListener("click",function(event){varusername=document.getElementById("username");console.log(username.checkValidity());if(username.checkValidity()){console.log("约束通过");}else{console.log("不通过");}},false);/script
要检测整个表单是否有效,可以在表单自身上调用checkValidity()方法;如果所有表单控件都有效,该方法返回true,即使其中一个表单无效,该方法都会返回false,如:
btn.addEventListener("click",function(event){if(document.forms[0].checkValidity()){console.log("约束通过");}else{console.log("不通过");}},false);
validity属性:checkValidity()方法只会返回是否有效的结果,但表单元素的validity属性则会返回有效或无效的原因,该属性是一个ValidityState类型的对象:
btn.onclick=function(){varnum=document.forms[0].elements["num"];console.log(num.validity);//ValidityState}
其包含一系列属性,每个属性会返回一个布尔值:
patternMismatch:如果值与指定的pattern属性不匹配,返回true;rangeOverflow:如果值比max值大,返回true;rangeUnderflow:如果值比min值小,返回true;stepMisMatch:如果step步长值不合理,返回true,step=“any”永远不会抛出此错误;tooLong:如果值的长度超过了maxlength属性指定的长度,返回true;有的浏览器会自动约束字符数量,因此这个值可能永远都返回false;tooShort:如果值的长度低于minlength属性指定的长度,返回true;typeMismatch:如果值不是”email”或”url”等要求的格式,返回true;valueMissing:如果标注为quid的元素中没有值,返回true;badInput:如果浏览器无法转换用户的输入,返回true;例如,number类型的输入元素,但其内容是字符串;customError:如果设置了setCustomValidity(),则为true,否则为false;valid:如果这里的其他属性都是false;checkValidity()方法也要求相同的值;
对于这些布尔属性中的每一个,值为true就表示验证失败;如果出现失败,浏览器将提醒用户并阻止提交表单;如果验证成功,即其他属性均返回false,则valid将为true,就可以提交表单;因此,要想得到更具体的信息,就应该使用validity属性来检测表单元素的有效性,如:
pinputtype="email"name="email"id="email"quidpattern="[a-zA-Z0-9_-]+
[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+"maxlength="10"//ppinputtype="button"id="btn"name="btn"value="按钮"//p/formscriptvarbtn=document.getElementById("btn");btn.addEventListener("click",function(event){varemail=document.getElementById("email");if(email.validity!email.validity.valid){if(email.validity.valueMissing)console.log("请输入数据");elseif(email.validity.typeMismatch)console.log("请输入邮件地址");elseif(email.validity.tooLong)console.log("超出长度");elseif(email.validity.patternMismatch)console.log("地址中不能包括特殊字符");elseconsole.log("啥玩意啊");}},false);/script
自定义错误信息:主要使用validationMessage属性和setCustomValidity()方法;如果没有通过验证,浏览器会有默认地提示信息,该信息保存在表单元素的validationMessage属性中,如:
varemail=document.forms[0].elements["email"];console.log(email.validationMessage);//如果有quid特性,提示"请填写此字段"varbtn=document.getElementById("btn");btn.addEventListener("click",function(event){varemail=document.getElementById("email");//根据不同的验证失败的原因,提示各自默认的信息if(email.validity!email.validity.valid){if(email.validity.valueMissing)console.log(email.validationMessage);//请填写此字段elseif(email.validity.typeMismatch)//请在电子邮件地址中包括“
”。“a”中缺少“”。console.log(email.validationMessage);elseif(email.validity.tooLong)console.log(email.validationMessage);elseif(email.validity.patternMismatch)//请与所请求的格式保持一致。console.log(email.validationMessage);elseconsole.log(email.validationMessage);}//或者//if(email.validity!email.validity.valid){//console.log(email.validationMessage);//}},false);
但是该属性是只读的,如果想修改这个值,可以调用setCustomValidity()改变validationMessage的值;如:
varemail=document.forms[0].elements["email"];email.setCustomValidity("不要懒,必须填!");email.validationMessage=这个字段必须填上。;console.log(email.validationMessage);
现在再单击提交,如果没有验证通过,会提示自定义的消息;如果将自定义错误设置为truthy值,则将阻止提交表单;因为调用了setCustomValidity()方法,所以validity的customError属性为true,导致validy属性为false,所以提交不了;
varbtnsubmit=document.querySelector(input[type="submit"]);btnsubmit.addEventListener("click",function(event){console.log(email.validationMessage);console.log(email.checkValidity());//false//customError:true,valueMissing:true,valid
alseconsole.log(email.validity);});
只有将自定义消息设置为空才能提交表单,而将自定义消息设置为空,也就是将消息恢复为浏览器默认的消息,如:
btnsubmit.addEventListener("click",function(event){if(email.value!=""){email.setCustomValidity("");}console.log(email.validationMessage);//默认的消息,地址包含
console.log(email.checkValidity());//false//typeMismatch:true,valid

alseconsole.log(email.validity);});
如果此时没有下一个约束,或者其他验证均有效的话,就可以顺利得交了;
当然,这些代码放到一个普通按钮的click事件处理程序中也是可以的,如:
varbtn=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();}});
可以根据不同的约束验证失败时分别自定义提示消息,如:
functionvalidate(input){varvalidityState=input.validity;if(validityState.valueMissing){input.setCustomValidity(必填);}elseif(validityState.typeMismatch){input.setCustomValidity(类型不正确);}elseif(validityState.rangeUnderflow){input.setCustomValidity(值太小);}elseif(validityState.rangeOverflow){input.setCustomValidity(值太大);}elseif(validityState.stepMisMatch){input.setCustomValidity(步长值不合理);}elseif(validityState.tooLong){input.setCustomValidity(长度超出了maxLength);}elseif(validityState.tooShort){input.setCustomValidity(长度小于minLength);}elseif(validityState.patternMismatch){input.setCustomValidity("格式不正确");}elseif(validityState.badInput){input.setCustomValidity(值类型无法转换);}else{input.setCustomValidity();}turnvalidityState.valid;}//应用varbtnsubmit=document.querySelector(input[type="submit"]);btnsubmit.addEventListener("click",function(event){varemail=document.getElementById("email");if(!validate(email)){console.log(email.validationMessage);console.log(email.checkValidity());console.log(email.validity);}});//或者普通按钮varbtn=document.getElementById("btn");btn.addEventListener("click",function(event){varemail=document.getElementById("email");if(!validate(email)){console.log(email.validationMessage);console.log(email.checkValidity());console.log(email.validity);}else{document.forms[0].submit();}});
也可以配合正则表达式,设备自定义错误消息,如:
formlabelfor="ZIP"邮编:/labelinputtype="text"id="ZIP"labelfor="Country"国家:/labelselectid="Country"optionvalue="cn"中国/optionoptionvalue="ch"瑞士/optionoptionvalue="fr"法国/optionoptionvalue="de"德国/optionoptionvalue="nl"荷兰/option/selectinputtype="submit"value="Validate"/formscriptfunctioncheckZIP(){//定义每个国家对应的,邮政编码必须遵循的模式及消息varconstraints={cn:[^(CN-)?\\d{5}$,"中国邮编需要5个数字:例如CN-22或22"],ch:[^(CH-)?\\d{4}$,"瑞士邮编需要4个数字:例如CH-或"],fr:[^(F-)?\\d{5}$,"法国邮编需要5个数字:例如F-或"],de:[^(D-)?\\d{5}$,"德国邮编需要5个数字:例如D-或"],nl:[^(NL-)?\\d{4}\\s*([A-RT-Z][A-Z]
S[BCE-RT-Z])$,"荷兰邮编需要4位数字,后跟除SA、SD和SS之外的2个字母"]};varcountry=document.getElementById("Country").value;varZIPField=document.getElementById("ZIP");//创建正则对象varconstraint=newRegExp(constraints[country][0],"");console.log(constraint);//检测if(constraint.test(ZIPField.value)){//通过约束校验ZIPField.setCustomValidity("");}else{//没有通过约束校验,设置当前国家的错误消息ZIPField.setCustomValidity(constraints[country][1]);}}window.onload=function(){document.getElementById("Country").onchange=checkZIP;document.getElementById("ZIP").oninput=checkZIP;}/script
novalidate属性和formnovalidate属性:禁用验证,可以设置表单不进行验证;
formname="myform"novalidate/form
在Javascript中使用noValidate属性可以获取或设置这个值,如果这个属性存在,值为true,否则为false;
document.forms[0].noValidate=true;//禁用验证
如果一个表单中有多个提交按钮,为了指定点击某个提交按钮不必验证表单,可以在相应的按钮上添加formnovalidate属性,如:
formname="myform"inputtype="submit"value="验证提交"/inputtype="submit"formnovalidatevalue="不验证提交"//form
使用Javascript也可以设置这个属性:
document.forms[0].elements["btnNoValidate"].formNoValidate=true;
一般情况下,表单使用novalidate属性关闭浏览器的自动校验的目的,就是使用脚本控制表单的校验;但是,这并不会禁止对约束校验的支持或对约束CSS伪类的支持;如:
styleinput:invalid{border-color
;background-color
FDD;}input
ocus:invalid{outline:none;}.error{color:white;background-color
ghtgen;padding:0.1em0.2em;}.error.active{background-color
;}/styleformnovalidatep邮箱 //或者if(username.validity.valueMissing){username.setCustomValidity(请输入用户名);}elseif(username.validity.patternMismatch){username.setCustomValidity(用户名只能包含大写和小写字母);}});//调用checkValidity()触发varbtn=document.getElementById("btn");btn.addEventListener("click",function(event){console.log(username.validity);if(!username.checkValidity()){//触发invalid事件console.log(username.validationMessage);}else{document.forms[0].submit();}});/script
:valid和:invalid伪类::validCSS伪类表示表单或表单元素数据验证通过的样式;:invalidCSS伪类表示表单或表单元素未通过验证样式;这两个伪类能简单地将校验字段展示为一种能让用户辨别出其输入数据的正确与否的样式;
styleform:invalid{border:5pxsolid#ffdddd;}form:valid{border:5pxsolid#ddffdd;}input:valid{background-color:powderblue;}input:invalid{background-color:pink;}/style
如:验证
stylediv{margin-bottom:10px;position:lative;}input[type="tel"]{width:px;}input+span{padding-right:30px;}input:invalid+span:after{position:absolute;content:;padding-left:5px;color
8b;}input:valid+span:after{position:absolute;content:;padding-left:5px;color
000;}/styledivlabelfor="tel"电话号码(必填):/labelinputid="tel"name="tel"type="tel"quidspanclass="validity"/span/div
:quid伪类和
ptional伪类::quidCSS伪类表示任意设置了quid属性的input、select或textaa元素;这个伪类对于高亮显示在提交表单之前必须具有有效数据的字段非常有用;
ptionalCSS伪类表示任意没有quid属性的input、select或textaa元素使用它;
input:quid{border:1pxsolidgen;}input
ptional{border:1pxdashedblack;}
:in-range伪类和
ut-of-range伪类:使用方式同上;
不使用内置表单校验API:对于老旧浏览器并不支持HTML的约束校验,因此只能使用JavaScript来校验表单数据,如:
styleinput.invalid{border-color
;background-color:#FDD;}input
ocus.invalid{outline:none;}.error{color:white;background-color
ghtgen;padding:0.1em0.2em;}.error.active{background-color
;}/styleformp邮箱