使用 Validate.JS 簡易完成表單驗證功能

什麼是 Validate.JS

Validate.JS 是一個表單驗證的函式庫,使用 Validate.JS 可以讓我們方便、快速的完成表單驗證的功能!點擊這裡可以先查看官網的簡易範例。

如何使用 Validate.JS

下載 Validate.JS

首先,我們可以透過不同的方式下載 Validate.JS

  1. CDN
    1
    <script src="https//cdnjs.cloudflare.com/ajax/libs/validate.js/0.13.1/validate.min.js">        </script>
  2. npm
    1
    2
    $npm install --save validate.js
    var validate = require("validate.js");

使用 Validate.JS 驗證欄位是否填寫

這邊先來介紹一下 validate.js 驗證器的基本格式,

1
2
3
4
5
6
7
<attribute>: { 
<validator name>: <validator options>
}

<屬性>: { // 屬性對應到 input 的 name
<驗證器名稱>: <驗證器選項>
}

而帶入語法後會長這樣:
1
2
3
4
// username 是必填欄位
username: { // 屬性會對應到 input 的 name,等於選取 `<input name="username">`
presence: true,
}

驗證器(validator)和驗證器選項(validator options)有很多。首先,我們先練習使用 Validate.JS 幫助我們判斷欄位是否填寫,我們需要用validate()函示來驗證欄位,帶入的參數如下:

1
2
// 透過驗證器(constraints)來驗證屬性(attributes),validate(屬性, 驗證器, [options]);
validate(attributes, constraints, [options]);

這裡的屬性(attributes)可以帶入物件或是表單(form)元素,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
// constraints 驗證器
let constraints = {
name: {
presence: true // name 欄位必填
}
};

// 屬性以物件帶入
validate({username: "nick", password: "better"}, constraints);

// 屬性以 form 元素帶入
const form = document.querySelector("#form");
validate(form, constraints);

validate() 執行後,驗證屬性,回傳錯誤訊息(如果沒有錯誤就不會回傳任何結果)

1
2
3
4
5
6
7
8
9
10
11
let constraints = {
name: {
presence: true // name 欄位必填
}
};

//驗證正確,回傳 undefined
validate({name: "nick"}, constraints);

//驗證錯誤,回傳 {"name":["Name can't be blank"]}
validate({name: ""}, constraints);

注意:
validate({}, from: {email: true});// 驗證正確,回傳undefined

原因是, null 和 undefined 是合法的值,所以如果不希望使用者輸入空的值,就要記得加上 presence: true。

了解了 validate() 的用法後,就可以搭配 form 標單寫成如下:

See the Pen validate.js 範例一 by 蔡蔡 Mavis (@0430shinyu) on CodePen.

送出空白欄位後,我們就可以在 console 面板看到回傳錯誤提示物件(若欄位填寫正確則會回傳 undefined。):

使用 Validate.JS 驗證欄位各種情境

除了驗證欄位是否填寫以外,Validate.JS 還包含了以下不同種的驗證:

1. datetime

datetime 可以用來驗證日期和時間。

在使用此驗證器之前,我們需要設置 parse 和 format 函數,
以及載入 moment.js(https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.6/moment.min.js)

moment.js 是一切和時間有關的的解析、轉換、設置、格式化日期的 JavaScript 函式庫

1
2
3
4
5
6
7
8
9
validate.extend(validate.validators.datetime, {
parse: function(value, options) {
return +moment.utc(value);
},
format: function(value, options) {
var format = options.dateOnly ? "YYYY-MM-DD" : "YYYY-MM-DD hh:mm:ss";
return moment.utc(value).format(format);
}
});

之後就可以使用 datetime: true 判斷是否符合格式 YYYY-MM-DD 或 YYYY-MM-DD hh:mm:ss,另外,也可以加上 dateOnly: true 限制只判斷格式是否符合 YYYY-MM-DD

1
2
3
4
5
validate({departure: "2013-12-11 10:09:08"}, {departure: {datetime: true}});
// => 驗證正確,回傳 undefined

validate({departure: "2013-12-11 10:09:08"}, {departure: {datetime: {dateOnly: true}}});
// => {"departure": ["Departure must be valid date"]}

我們也可以搭配 moment.js 和 latest(日期前)與 earliest(日期後) 做年齡的判斷

1
2
3
4
5
6
7
8
9
10
11
var constraints = {
birthday: {
datetime: {
dateOnly: true, // 確認是否符合有效格式 YYYY-MM-DD
latest: moment.utc().subtract(18, 'years'), //年齡必須在 18 歲以上
message: "^You need to be at least 18 years old" // 回傳的錯誤訊息
}
}
};
validate({birthday: "3013-11-14"}, constraints);
// {"birthday": ["You need to be at least 18 years old"]}

2. email

email 可以判斷信箱是否為有效格式

1
2
3
4
5
6
7
8
9
10
11
12
13
let constraints = {
from: {
email: true
}
};

validate({from: "nicklas@ansman"}, constraints);
// => {"email": ["From is not a valid email"]}


// Upper cased emails are allowed
validate({from: "NICKLAS@ANSMAN.SE"}, constraints);
// => 驗證正確,回傳 undefined

email 一樣也可以透過 message 回傳錯誤訊息,如果希望 messsage 省略預設的屬性名稱(form)可以加上 ^ 寫成 “^doesn’t look like a valid email”。

1
2
3
4
5
6
7
8
9
10
constraints = {
from: {
email: {
message: "doesn't look like a valid email"
}
}
};

validate({from: "foobar"}, constraints);
// => {"email": ["From doesn't look like a valid email"]}

3.equality
equality 可用來驗證屬性是否等於另一個屬性,常使用在設定密碼時的密碼確認。

1
2
3
4
5
6
7
8
9
10
11
let constraints = {
confirmPassword: {
equality: "password" //要判斷是否相同的對屬性
}
};

validate({password: "foo", confirmPassword: "foo"}, constraints);
// => 驗證正確,回傳 undefined

validate({password: "foo", confirmPassword: "bar"}, constraints);
// => {confirmPassword: ["Confirm password is not equal to password"]}

4.exclusion
Exclusion 可用來驗證值是否在特定陣列中,如果在陣列中就排除

1
2
3
4
5
6
7
8
var restrictedDomains = ;

validate({subdomain: "tw"}, {subdomain: {exclusion: ["jp", "ch"]}});
// => 驗證正確,回傳undefined

validate({subdomain: "jp"}, {subdomain: {exclusion: ["jp", "ch"]}});
// => {"size": ["jp is restricted"]}

我們也可以使用 within 搭配 ${value}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let constraints = {
subdomain: {
exclusion: {
within: {jp: "Japan", ch: "China"},
message: "^We don't support %{value} right now, sorry"
}
}
};

validate({subdomain: "jp"}, constraints);
// => {"subdomain": ["We don't support Japan right now, sorry"]}

validate({subdomain: "com"}, constraints);
// => 驗證正確,undefined

5.inclusion
Inclusion 可用來驗證值是否在特定陣列中,如果不在陣列中就排除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
let sizes = ["small", "medium", "large"];

validate({"small"}, {size: {inclusion: sizes}});
// => undefined

validate({size: "xlarge"}, {size: {inclusion: sizes}});
// => {"size": ["xlarge is not included in the list"]}

let constraints = {
size: {
inclusion: {
within: {"Small": "s", "Medium": "m", "Large": "l"},
message: "^We're currently out of %{value}"
}
}
};

validate({size: "Extra large"}, constraints);
// => {"size": ["We're currently out of Extra large"]}

validate({size: "Medium"}, constraints);
// => 驗證正確,回傳 undefined

6.format
format 可以使用正規表達式驗證欄位是否符合,Validate.JS 沒有提供的格式(如:郵遞區號),就可以使用 format 做驗證

1
2
3
4
5
6
7
let pattern = /\d{5}(-\d{4})?/;

validate({zipCode: "foobar"}, {zipCode: {format: pattern}});
// => {"zipCode": ["Zip code is invalid"]};

validate({zipCode: "12345"}, {zipCode: {format: pattern}});
// => 驗證正確,回傳 undefined

如果需要使用到 flags 需要再另外加上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var constraints = {
username: {
format: {
pattern: "[a-z0-9]+",
flags: "i",
message: "can only contain a-z and 0-9"
}
}
};

validate({username: "Nicklas!"}, constraints);
// => {"username": ["Username can only contain a-z and 0-9"]}

validate({username: "Nicklas"}, constraints);
// => 驗證正確,回傳 undefined

7.length

length 可以用來判斷是否符合長度,is 代表等於,代表小於,代表大於,也可使用
tooShort、tooLong、notValid 和 wrongLength 修改預設錯誤訊息

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
let constraints = {
key1: {length: {is: 3}}, // 長度等於 3
key2: {length: {minimum: 20}}, // 長度小於 20
key3: {length: {maximum: 3}}, // 長度大於 3
key4: {
length: {
minimum: 3,
tooShort: "needs to have %{count} words or more",
tokenizer: function(value) {
return value.split(/\s+/g);
}
}
}
};

validate({}, constraints);

var values = {
key1: "wrong length",
key2: "too short",
key3: "too long",
key4: "too short"
};
validate(values, constraints);
// => {
// "key1": ["Key1 is the wrong length (should be 3 characters)"],
// "key2": ["Key2 is too short (minimum is 20 characters)"],
// "key3": ["Key3 is too long (maximum is 3 characters)"],
// "key4": ["Key4 needs to have 3 words or more"]
// }

8.numericality

numericality可以判斷是否只填入數字,沒有填入其他型態的內容。

1
2
3
4
5
6
7
8
validate({duration: "foobar"}, {duration: {numericality: true}});
// => {"duration": ["Duration is not a number"]}

validate({duration: "3"}, {duration: {numericality: true}});
// => 驗證正確,回傳 undefined

validate({duration: "03"}, {duration: {numericality: true}});
// => 驗證正確,回傳 undefined

strict:數字不可以0作為開頭

1
2
validate({duration: "03"}, {duration: {numericality: {strict: true}}});
// => {"duration": ["Duration must be a valid number"]}

noStrings:數字不可以0作為開頭

1
2
3
4
5
validate({duration: "3"}, {duration: {numericality: {noStrings: true}}});
// => {"duration": ["Duration is not a number"]}

validate({duration: 3}, {duration: {numericality: {noStrings: true}}})
// 驗證正確,回傳 undefined

noStrings:數字可以整除數字 n

1
2
validate({duration: "7"}, {duration: {numericality: {divisibleBy: 3}}});
// => {"duration": ["Duration must be divisible by 3"]}

還有其他不同的設定:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var constraints = {
duration: {
numericality: {
onlyInteger: true,
greaterThan: 0, // 大於 0
lessThanOrEqualTo: 30, // 小於或等於 30
even: true, //偶數
notEven: "must be evenly divisible by two" // 非偶數回傳的錯誤訊息
}
}
};

validate({duration: 3.14}, constraints);
// => {"duration": ["Duration must be an integer"]}

validate({duration: 4711}, constraints);
// => {
// "duration": [
// "Duration must be less than or equal to 30",
// "Duration must be evenly divisible by two"
// ]
// }

9.url

url 可以判斷網址是否有效。

1
2
3
4
5
6
7
8
validate({website: "http://google.com"}, {website: {url: true}});
// => undefined

validate({website: "google.com"}, {website: {url: true}});
// => {"website": ["Website is not a valid url"]}

validate({website: "ftp://google.com"}, {website: {url: true}});
// => {"website": ["Website is not a valid url"]}

schemes :允許的 schemes,預設為 [“http”, “https”]。

1
2
3
4
5
6
7
8
validate({website: "ftp://google.com"}, {
website: {
url: {
schemes: ["ftp"]
}
}
});
// => undefined

allowLocal:允許 local 主機名稱,如:10.0.1.1 或 localhost。預設為 false

1
2
3
4
5
6
7
8
9
10
11
validate({website: "http://localhost"}, {website: {url: true}});
// => {"website": ["Website is not a valid url"]}

validate({website: "http://localhost"}, {
website: {
url: {
allowLocal: true
}
}
});
// => undefined

回傳結果給使用者

前面我們已經了解到如何使用 Validate.js 做驗證,但只在 console 面板顯示錯誤提示,無法真正提醒使用者。我們可以透過點擊送出按鈕後隱藏、顯示文字來提醒使用者,例如:

See the Pen validate.js 範例二 by 蔡蔡 Mavis (@0430shinyu) on CodePen.

參考資料

Validate.JS 官網


使用 Validate.JS 簡易完成表單驗證功能
https://shinyu0430.github.io/2022/01/09/validatejs/
作者
Mavis Tsai
發布於
2022年1月9日
許可協議