表單在網頁上的應用很頻繁,也是與使用者互動的重要部分,凡舉聯絡的表單,或是資料的填寫、登入,都會用到表單,透過表單所得取的資料,如果不符合格式,也會造成後續資料處理上的麻煩與困難,雖然我們也可以透過 HTML5 來驗證使用者填入的是否符合一些基本的規則,但是無法定義比較細微的部分,這時候就必須自己動手寫驗證了。
好工具哪有不用的道理
如果自己寫過表單的驗證,就會知道其實是很瑣碎的,在邏輯的處理上也必須花些心思,如果能力許可當然可以自己寫一個套件來用,但是套件如果別人寫的又好又完善,也真的可以不需要自己刻。
使用套件的心態或許可以放在:「套件會用就好」,第一時間或許不需要了解原始碼怎麼寫,但一定要遵循官方文件,來理解如何使用,且官網的文件解說與使用說明大都很清楚,也就很容易上手。待有多的時間再來翻看原始碼也不遲。
validate.js 便是一個完善的套件,表單需要的驗證該有的都有,而且引入就可以使用了,那麼就來理解一下,如何使用 validate.js 來驗證表單。
起手式,先引入
validate.js 官網 | CDN | 示範
最簡單的引入方試試使用 CDN 將 validate.js 引入頁面,接著就可以開始一官方文件的格式來寫要驗證的規則,也就是官網的 Constraints(約束條件)部分。
驗證的規則(約束條件)
validate.js 驗證的規則為物件,如果有多個驗證的規則,可在 constraints
的物件裡增加多個約束條件。
1 2 3 4 5 6
| { <attribute>: { <validator name>: <validator options>, } }
|
例如信用卡的輸入,presence: true
是最基礎的條件,表示必填。
1 2 3 4 5
| const constraints = { creditCardNumber: { presence: true, }
|
自定義條件規則
以登入的表單來說,需要填寫帳號和密碼,兩個 input 都是必填,而條件的物件屬性名稱,對應的就是 HTML input 裡的name
屬性。
1 2 3 4 5 6 7 8 9 10
| const constraints = { account: { presence: true, length: { minimum: 20 }, }, password: { presence: true, }, };
|
寫條件時的對應屬性名稱,可以在官網的Validators
查詢,以密碼的長度驗證來說,在官網為Validators
–> Length
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| var constraints = { key1: { length: { is: 3 } }, key2: { length: { minimum: 20 } }, key3: { length: { maximum: 3 } }, key4: { length: { minimum: 3, tooShort: 'needs to have %{count} words or more', tokenizer: function (value) { return value.split(/\s+/g); }, }, }, };
|
當使用者填入資料時會去執行validate function
透過這個函式來回傳是否驗證成功,如如被驗證出不符合條件時,就會跳出警告訊息
validate function
validate function 共有三個參數,前兩個必填。
1
| validate validate(attributes, constraints, [options]){...}
|
參數說明:
attributes:物件的形式或表單元素
constraints:驗證規則物件
表單內的name=""
的值一定要寫,因為 Validate.Js 是根據 name 來抓取驗證的元素。以下是登入表單的驗證範例:
1 2 3 4
| <form id="myForm"> <input type="text" class="username" name="username" /> <input type="password" class="username" name="password" /> </form>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| const form = document.querySelector('form#myForm');
const constraints = { username:{ presence:{ message: "必填欄位" length: { minimum: 20 }, }, }, password:{ presence: true, } };
const errors = validate(form, constraints);
|
範例 驗證各欄位
和 validate 對應的為 input 裡的 name 屬性,為了區分每各欄位驗證的錯誤訊息,在每各欄位下方加上一個 class 為 message 的 div,並各增加同名的 class,例如:<div class="messages description"></div>
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| <form id="myForm"> <label for="">套票名稱</label> <input type="text" name="name" /> <div class="messages name"></div>
<label for="">圖片網址</label> <input type="text" name="imgUrl" /> <div class="messages imgUrl"></div>
<label for="">景點地區</label> <select name="area"> <option value="" selected disabled>選擇地區</option> <option value="台北">台北</option> <option value="台中">台中</option> <option value="高雄">高雄</option> </select> <div class="messages area"></div>
<label for="">套票金額</label> <input type="number" name="price" min="0" /> <div class="messages price"></div>
<label for="">套票組數</label> <input type="number" name="group" min="0" /> <div class="messages group"></div>
<label for="">套票星級</label> <input type="number" name="rate" min="0" max="10" /> <div class="messages rate"></div>
<label for="">套票描述</label> <textarea type="text" name="description"></textarea> <div class="messages description"></div>
<button type="submit">新增套票</button> </form>
|
如需其他驗證規則,可至官方網站的 Validators 去查詢還有哪些方法和條件可以加入。在寫條件的物件裡,也可以自行新增屬性,在這裡我們增加了messages
的屬性,以顯示不同的錯誤訊息。
之後就會讓
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
|
const constraints = { name: { presence: { message: '是必填欄位', }, }, imgUrl: { presence: { message: '是必填欄位', }, url: { schemes: ['http', 'https'], message: '必須是正確的網址', }, }, area: { presence: { message: '是必填欄位', }, }, price: { presence: { message: '是必填欄位', }, numericality: { greaterThan: 0, message: '必須大於 0', }, }, group: { presence: { message: '是必填欄位', }, numericality: { greaterThan: 0, message: '必須大於 0', }, }, rate: { presence: { message: '是必填欄位', }, numericality: { greaterThanOrEqualTo: 1, lessThanOrEqualTo: 10, message: '必須符合 1-10 的區間', }, }, description: { presence: { message: '是必填欄位', }, length: { maximum: 1000, message: '不可超過 10000 的字元', }, }, };
const form = document.querySelector('form#myForm');
const inputs = document.querySelectorAll( 'input[type=text],input[type=number],select,textarea' );
inputs.forEach((item) => { item.addEventListener('change', function () { item.nextElementSibling.textContent = ''; let errors = validate(form, constraints); console.log(errors);
if (errors) { Object.keys(errors).forEach(function (keys) { console.log(keys); document.querySelector(`.${keys}`).textContent = errors[keys]; }); } }); });
|
顯示方式取決於監聽事件的方式,並以抓取到的 DOM 元素來跑 forEach()
,來監聽每一個 input。可以把抓取的元素來跑forEach()
是因為,當我們使用querySelectorAll
來抓取元素時,回傳的就是陣列格式。
nextElementSibling
為同層的下一個元素,因為每個同層的 input 的下一個,都是顯示訊息的 message 所以可使用它來處理預設為空,達到更動後清空提示訊息的效果。
收集到的 errors 是物件無法使用陣列方法forEach()
,所以使用 Object.keys 先取到物件的屬性,並返回陣列,就可以以forEach()
去跑迴圈,將拿到的 keys 也就是透過物件取值的方法,拿到對應的 keys (錯誤訊息),再放入每個元素的 errors 的 DOM 裡顯示。
前置作業我們把 input 的 name 和 顯示錯誤的 Dom 的 class 名稱取成一樣,所以可以有辦法透過querySelector
的 class 名稱去抓取物件的值。
後記
這個套件使用的機率頗高,相信在操作幾次之後就會讓開發專案的時候更容易自定義每個鏢單欄位的驗證條件。如果是以框架開發,也可以以 npm 的方式增加這個驗證模組,非常方便。