整合營銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          第65節(jié) 表單數(shù)據(jù)校驗(yàn)(驗(yàn)證)-Web前端開發(fā)之JavaScript-王唯

          內(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" />

          其擁有屬性:

          • max:設(shè)置或返回滑塊控件的最大值;
          • min:設(shè)置或返回滑塊控件的最小值;
          • step:設(shè)置或返回每次拖動(dòng)滑塊控件時(shí)的遞增量;
          • value:設(shè)置或返回滑塊控件的 value 屬性值;
          • defaultValue:設(shè)置或返回滑塊控件的默認(rèn)值;
          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è)布爾值:

          • patternMismatch:如果值與指定的pattern屬性不匹配,返回true;
          • rangeOverflow:如果值比max值大,返回true;
          • rangeUnderflow:如果值比min值小,返回true;
          • stepMisMatch:如果step步長值不合理,返回true,step=“any”永遠(yuǎn)不會(huì)拋出此錯(cuò)誤;
          • tooLong:如果值的長度超過了maxlength屬性指定的長度,返回true;有的瀏覽器會(huì)自動(dòng)約束字符數(shù)量,因此這個(gè)值可能永遠(yuǎn)都返回false;
          • tooShort:如果值的長度低于minlength屬性指定的長度,返回true;
          • typeMismatch:如果值不是”email”或”url”等要求的格式,返回true;
          • valueMissing:如果標(biāo)注為required的元素中沒有值,返回true;
          • badInput:如果瀏覽器無法轉(zhuǎn)換用戶的輸入,返回true;例如,number類型的輸入元素,但其內(nèi)容是字符串;
          • customError:如果設(shè)置了setCustomValidity(),則為true,否則為false;
          • valid:如果這里的其他屬性都是false;checkValidity()方法也要求相同的值;

          對于這些布爾屬性中的每一個(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)證的注解:

          • @Size(min=2, max=30) name的長度為2-30個(gè)字符
          • @NotNull 不為空
          • @Min(18)age不能小于18

          創(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)很多自定義效果


          主站蜘蛛池模板: 国产一区二区三区高清在线观看| 免费一区二区三区四区五区| 乱码精品一区二区三区 | 美女免费视频一区二区| 亚洲色一区二区三区四区| 天天躁日日躁狠狠躁一区| 精品无人区一区二区三区 | 日本亚洲成高清一区二区三区| 无码人妻久久一区二区三区免费 | 国产一区二区三区免费看| 国产在线无码视频一区| 久久亚洲中文字幕精品一区| 国产成人精品视频一区二区不卡| 97久久精品无码一区二区| 国产精品视频免费一区二区三区| 精品亚洲一区二区三区在线播放| 亚洲无线码一区二区三区| 伊人久久精品无码麻豆一区| 日本高清天码一区在线播放| 国产一区二区三区免费观看在线| 91精品一区二区综合在线| 国产SUV精品一区二区88L| 国产AV午夜精品一区二区入口| 中文精品一区二区三区四区| 国产免费播放一区二区| 亚洲一区二区三区国产精品无码| 国产一区二区三区免费在线观看| 国产精品熟女一区二区| 国语对白一区二区三区| 亚洲国产精品一区二区成人片国内| 国产经典一区二区三区蜜芽| 精品人体无码一区二区三区| av一区二区三区人妻少妇| 国产午夜福利精品一区二区三区 | 一区二区在线免费视频| 91精品国产一区| 亲子乱av一区二区三区| 国产精品久久亚洲一区二区| 色欲AV蜜臀一区二区三区| 国产精品福利区一区二区三区四区| 精品国产一区二区三区香蕉|