前言:表單驗證是十分常見的需求。公司做運維系統需要大量的編輯/新增表單,編輯之后提交,提交前需要進行表單驗證,驗證成功才能發起POST請求。由於項目前端大部分是基於Bootstrap開發的,可看官網Bootstrap Validator http://1000hz.github.io/bootstrap-validator/,感覺比較容易上手。用bootstrap validator有個問題,需驗證的input/select等標簽的外部需要有一個<div class="form-group">包着,驗證失敗時給class="form-group"的div變成紅色。

1 <form data-toggle="validator" role="form"> 2 <div class="form-group"> 3 <label for="inputName" class="control-label">Name</label> 4 <input type="text" class="form-control" id="inputName" placeholder="Cina Saffary" required> 5 </div> 6 <div class="form-group has-feedback"> 7 <label for="inputTwitter" class="control-label">Twitter</label> 8 <div class="input-group"> 9 <span class="input-group-addon">@</span> 10 <input type="text" pattern="^[_A-z0-9]{1,}$" maxlength="15" class="form-control" id="inputTwitter" placeholder="1000hz" required> 11 </div> 12 <span class="glyphicon form-control-feedback" aria-hidden="true"></span> 13 <div class="help-block with-errors">Hey look, this one has feedback icons!</div> 14 </div> 15 <div class="form-group"> 16 <label for="inputEmail" class="control-label">Email</label> 17 <input type="email" class="form-control" id="inputEmail" placeholder="Email" data-error="Bruh, that email address is invalid" required> 18 <div class="help-block with-errors"></div> 19 </div> 20 <div class="form-group"> 21 <label for="inputPassword" class="control-label">Password</label> 22 <div class="form-inline row"> 23 <div class="form-group col-sm-6"> 24 <input type="password" data-minlength="6" class="form-control" id="inputPassword" placeholder="Password" required> 25 <div class="help-block">Minimum of 6 characters</div> 26 </div> 27 <div class="form-group col-sm-6"> 28 <input type="password" class="form-control" id="inputPasswordConfirm" data-match="#inputPassword" data-match-error="Whoops, these don't match" placeholder="Confirm" required> 29 <div class="help-block with-errors"></div> 30 </div> 31 </div> 32 </div> 33 <div class="form-group"> 34 <div class="radio"> 35 <label> 36 <input type="radio" name="underwear" required> 37 Boxers 38 </label> 39 </div> 40 <div class="radio"> 41 <label> 42 <input type="radio" name="underwear" required> 43 Briefs 44 </label> 45 </div> 46 </div> 47 <div class="form-group"> 48 <div class="checkbox"> 49 <label> 50 <input type="checkbox" id="terms" data-error="Before you wreck yourself" required> 51 Check yourself 52 </label> 53 <div class="help-block with-errors"></div> 54 </div> 55 </div> 56 <div class="form-group"> 57 <button type="submit" class="btn btn-primary">Submit</button> 58 </div> 59 </form>
一、跳過的坑
后來沒用Bootstrap Validator, 用了jquery.validate.js插件。https://jqueryvalidation.org/,接下來學習jquery.validate.js,有點懶,直接用英文,不懂的可以評論問我,我在form表單驗證踩了很多坑,比較有體會……
最開始用jquery.validate.js時,用來驗證Bootstrap模態框的Form表單,媽蛋,竟然驗證不了,根本沒有反應。搞了很久很久,才知道是因為用模態框時,submit按鈕沒有放在Form表單里面,所以觸發不了驗證。后來改用Bootstrap Validator,尼媽,得給要驗證的input/select標簽外的標簽(驗證不通過會變紅)加上class="form-group",但是加上form-group屬性后我的表單樣式出錯了(變丑了),怎么辦,我只想給這個標簽加上form-group屬性,但是不希望它帶上form-group的樣式,正所謂有名無實……我當時不懂,一直用瀏覽器調前端界面,然而並沒有什么卵用,后來請教隔壁組做前端的PHP大神,給這個標簽的class最后加上自定義的樣式,覆蓋前面form-group的樣式,前后只花了一兩分鍾,頓時膜拜銘哥大佬。比如說A標簽的class有兩個屬性class="a b"當a和b的樣式有沖突是,比時a樣式是margin-top:10px,而b樣式是margin-top:20px,這時會選取class最后的樣式,b在a的后面,當a,b樣式沖突時,會優先取b的樣式。具體代碼現在沒有,要的話明天去公司的SVN找找看……
后來項目被我改用layer彈框,而不是模態框,老大讓我做一個表單驗證的接口……
因為總不能每一個HTML文件都寫那么多JS來驗證Form表單。驗證接口參考了老大前公司的代碼(TC公司)。
首先,頁面初始化完成時,調用表單驗證接口validate_interface
<script>
// layer.ready(callback) - 初始化就緒
$(document).ready(function () { var form_obj = $("#edit_instance_data"); validate_interface(form_obj); // 調用包裝好的接口進行表單驗證與ajax請求
}); </script>
封裝好的表單驗證接口+Ajax請求接口+關閉layer彈框接口。
接下來用插件自帶的invalidHandler得出有多少個標簽不通過驗證。再利用noty插件彈出提示信息。這里我簡單看了noty插件,直接會用就行了。
看我下面的代碼closest是什么意思,嗯,當時我也不知道,后來去查了下JQ,知道是從當前標簽一層一層外外找,直至找到。
$(element).closest('.selectpicker')
這句代碼的意思是從當前標簽一層一層往外找,直至找到class="selectpicker"的標簽。
看我接口的代碼會發現有highlight、success 的一些方法。這主要是因些我的form表單用了bootstrap-select插件來美化select標簽,但是jquery.validate.js無法驗證bootstrap-select的select標簽,只能在提交表單時才會驗證。這是個很奇葩的坑,我跳進出很久都出不來。網上stackoverflow看了很多解決方法,也沒有什么用,是我姿勢不對?
后來在一篇stackoverflow找到解決方法
form_obj.find("select").on('change', function(e) { console.log($(this)); // 手動調用select標簽 $('.form-horizontal').validate().element($(this)); });
當驗證不通過時,給標簽(class:my-validate)加上has-error has-feedback屬性,這樣標簽的邊框就會變紅。
$(element).closest('.my-validate').addClass('has-error has-feedback');
當驗證通過時,移除對應的樣式
label.closest('.my-validate').removeClass('has-error has-feedback');
二、以下是接口的代碼,希望對你有幫助:
1 // 封裝好的表單驗證接口與ajax請求
2 function validate_interface(form_obj){ 3 form_obj.validate({ 4 invalidHandler: function(event, validator) { 5 // 驗證不通過的數量
6 var errors = validator.numberOfInvalids(); 7 if (errors) { 8 console.log("errors", errors); 9 var msg = errors == 1 ? "你有 1 個必填字段未填,已經加紅顯示." : "你有 " + errors + " 個必填字段未填,已經加紅顯示。"; 10 console.log("msg", msg); 11 noty({ 12 text: msg, 13 type: "error", 14 timeout: 1500
15 }); 16 } 17 }, 18 highlight : function(element) { 19 console.log(element.tagName); 20 $(element).closest('.my-validate').addClass('has-error has-feedback'); 21 $(element).closest('.selectpicker').selectpicker('refresh'); 22 }, 23 //驗證通過的處理
24 success : function(label) { 25 console.log("label", label); 26 label.closest('.my-validate').removeClass('has-error has-feedback'); 27
28 }, 29
30 submitHandler: function(form) { 31 console.log("form", form); 32 // ajax request after form validate true!
33 ajax_func(); 34
35 } 36
37
38 }); 39
40
41 form_obj.find("select").on('change', function(e) { 42 console.log($(this)); 43 $('.form-horizontal').validate().element($(this)); 44 }); 45
46 // 點擊彈出框的確認按鈕調用該函數
47 function ajax_func() { 48 var ajax_post_url = form_obj.attr("ajax_post_url"); 49 console.log("form_msg", form_obj.serialize()); 50 $.ajax({ 51 url: ajax_post_url, // 提交的頁面
52 data: form_obj.serialize(), // 從表單中獲取數據
53 type: "POST", // 設置請求類型為"POST",默認為"GET"
54 error:function (jqXHR, textStatus, errorThrown) { 55 alert(jqXHR.responseText); 56 alert(jqXHR.status); 57 }, 58 success: function(data) { 59 var index = parent.layer.getFrameIndex(window.name); //先得到當前iframe層的索引
60 console.log("index", index); 61 parent.layer.close(index); //再執行關閉
62 alert("提交成功"); 63 } 64 }); 65 } 66 } 67
68
69 // interface of close layer
70 function close_layer() { 71 console.log("layer inter close"); 72 var index = parent.layer.getFrameIndex(window.name); //先得到當前iframe層的索引
73 parent.layer.close(index); //再執行關閉
74 return false; 75 }
驗證一通過則發起ajax請求,ajax請求成功扣則關閉當前layer彈框,對layer不了解的可以看我下篇博客……
三、自定義驗證
接下來又有個新需求,DBA騰哥要我驗證表單,比如用戶輸入只能由字母、數字、下划線組成……還有IP地址,發須是IP的格式才能通過驗證,給后台發起請求。
這就需要自定義表單驗證方法,比如你想驗證文本框驗證的是不是IP地址,可以自定義表單驗證方法,自己寫正則表達式進行匹配,匹配不通過是顯示自定義的錯誤信息。
1 // layer.ready(callback) - 初始化就緒
2 $(document).ready(function () { 3 var form_obj = $("#edit_workflow"); 4
5 validate_interface(form_obj); // 調用包裝好的接口進行表單驗證與ajax請求
6
7 var url = location.search; 8 $("#url").val(url); 9
10 // my first validator function
11 jQuery.validator.addMethod("my_first_validator", function(value, element) { 12 return this.optional(element) || /^[a-zA-Z0-9_]+$/.test(value); 13 }, "用戶名只能由字母、數字、下划線組成"); 14
15 // my second validator function
16 jQuery.validator.addMethod("my_second_validator", function(value, element) { 17 return this.optional(element) || /^[^\s]*$/.test(value); 18 }, "密碼不能包含空格"); 19
20 // my third validator function
21 jQuery.validator.addMethod("my_third_validator", function(value, element) { 22 // 正則匹配文本框的IP
23 return this.optional(element) || /^(\s)*(([0-9]{1,3}\.){3}[0-9]{1,3}(\s)*)+(\s)*$/.test(value); 24 }, "ip格式不對,多個ip請用換行符分開!"); 25
26 });
至此,表單驗證ending,如果你是第一次了解表單驗證,想必你看完這篇博客也是一臉蒙逼的,你應該看了官網,我下面選了jquery.validate.js官網我覺得我有必要記錄的一部分。可以看看,不爽就自己去看官網。
對了,還有一個坑,百度/谷哥jquery.validate.js,會出現博客園的這篇文章jQuery驗證控件jquery.validate.js使用說明+中文API,當時我想自定義錯誤信息,網上很多方法有用如下代碼的方法,但我也引入了jquery.metadata.js,然而並沒有反應。fuck!
使用class="{}"的方式,必須引入包:jquery.metadata.js 可以使用如下的方法,修改提示內容: class="{required:true,minlength:5,messages:{required:'請輸入內容'}}"
解決方法:這個問題的實質是,我要對select標簽進行驗證,比如該標簽是必填的,那我肯定要給標簽加上required=“true",但是輸入內容長度要如何加在標簽?用上面代碼的方法是不行的!! 還有,如果你自定義了驗證方法,比如前端我自定義驗證IP,那我如何讓標簽驗證時調用這寫的驗證方法。其實很簡單,沒啥技術含量。看代碼,代碼現在沒有,明天上班再看看
-----------------------分割線-----------------------
四、jquery.validate.js記錄
submitHandler (default: native for m submit
)
Example: Submits the form via Ajax when valid.
$("#myform").validate({ submitHandler: function(form) { $(form).ajaxSubmit(); } });
Example: Use submitHandler to process something and then using the default submit. Note that "form" refers to a DOM element, this way the validation isn't triggered again.
$("#myform").validate({ submitHandler: function(form) { // do other things for a valid form
form.submit(); } });
invalidHandler
Example: Displays a message above the form, indicating how many fields are invalid when the user tries to submit an invalid form.
$("#myform").validate({ invalidHandler: function(event, validator) { // 'this' refers to the form var errors = validator.numberOfInvalids(); if (errors) { var message = errors == 1 ? 'You missed 1 field. It has been highlighted' : 'You missed ' + errors + ' fields. They have been highlighted'; $("div.error span").html(message); $("div.error").show(); } else { $("div.error").hide(); } } });
success
Example: Add a class "valid" to valid elements, styled via CSS.
$("#myform").validate({ success: "valid", submitHandler: function() { alert("Submitted!") } });
Example: Add a class "valid" to valid elements, styled via CSS, and add the text "Ok!".
$("#myform").validate({ success: function(label) { label.addClass("valid").text("Ok!") }, submitHandler: function() { alert("Submitted!") } });
The callback gets passed two arguments:
-
labelType: jQueryThe error label. Use to add a class or replace the text content.
-
elementType: ElementThe element currently being validated, as a DOMElement.
ignore (default: ":hidden"
)
Example: Ignores all elements with the class "ignore" when validating.
$("#myform").validate({ ignore: ".ignore" });
highlight (default: Adds errorClass (see the option) to the element
)
Example: Adds the error class to both the invalid element and its label
$("#myform").validate({ highlight: function(element, errorClass, validClass) { $(element).addClass(errorClass).removeClass(validClass); $(element.form).find("label[for=" + element.id + "]") .addClass(errorClass); }, unhighlight: function(element, errorClass, validClass) { $(element).removeClass(errorClass).addClass(validClass); $(element.form).find("label[for=" + element.id + "]") .removeClass(errorClass); } })
The callback gets passed three arguments:
- element
Type: Element
The invalid DOM element, usually an input
.
- errorClass
Type: String
Current value of the errorClass
option.
- validClass
Type: String
Current value of the validClass
option.
unhighlight (default: Removes the errorClass
)
Type: Function()
Called to revert changes made by option highlight, same arguments as highlight.