[實作] 表單驗證

HTML

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Form Validator</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="container">
<!-- form#form.form -->
<form action="" id="form" class="form">
<h2>Register With Us</h2>
<div class="form-control">
<label for="username">Username</label>
<!-- input#username -->
<input type="text" id="username" placeholder="Enter username" />
<small>Error message</small>
</div>
<div class="form-control">
<label for="email">Email</label>
<input type="text" id="email" placeholder="Enter email" />
<small>Error message</small>
</div>
<div class="form-control">
<label for="password">Password</label>
<input
type="password"
id="password"
placeholder="Enter password"
autocomplete="on"
/>
<small>Error message</small>
</div>
<div class="form-control">
<label for="password2">Confirm password</label>
<input
type="password"
id="password2"
placeholder="Enter password again"
autocomplete="on"
/>
<small>Error message</small>
</div>
<button>Submit</button>
</form>
</div>
<script src="script.js"></script>
</body>
</html>

CSS

Css的變數使用

1
2
3
4
:root{
--success-color: #2ecc71;
--error-color: #e74c3c;
}

利用Js動態存取Css

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
.form-control.success input {
border-color: var(--success-color);
}

.form-control.error input {
border-color: var(--error-color);
}

.form-control small {
color: var(--error-color);
position: absolute;
bottom: 0;
left: 0;
visibility: hidden;
}

.form-control.error small {
visibility: visible;
}

完整Code

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
92
93
94
95
96
97
98
@import url("https://fonts.googleapis.com/css2?family=Open+Sans&display=swap");

/* 變數 */
:root {
--success-color: #2ecc71;
--error-color: #e74c3c;
}

* {
box-sizing: border-box;
}

body {
background-color: #f9fafb;
font-family: "Open Sans", sans-serif;
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
margin: 0;
}

.container {
background-color: #fff;
border-radius: 5px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
width: 400px;
}

h2 {
text-align: center;
margin: 0 0 20px;
}

.form {
padding: 30px 40px;
}

.form-control {
margin-bottom: 10px;
padding-bottom: 20px;
position: relative;
}

.form-control label {
color: #777;
display: block;
margin-bottom: 5px;
}

.form-control input {
border: 2px solid #f0f0f0;
border-radius: 4px;
display: block;
width: 100%;
padding: 10px;
font-size: 14px;
}

.form-control input:focus {
outline: 0;
border-color: #777;
}

/* dynamic with javascript */
/* js存取時才出現 */
.form-control.success input {
border-color: var(--success-color);
}

.form-control.error input {
border-color: var(--error-color);
}

.form-control small {
color: var(--error-color);
position: absolute;
bottom: 0;
left: 0;
visibility: hidden;
}

.form-control.error small {
visibility: visible;
}

.form button {
cursor: pointer;
background-color: #3498db;
border: 2px solid #3498db;
border-radius: 4px;
color: white;
font-size: 16px;
padding: 10px;
margin-top: 20px;
width: 100%;
}

Javascript

利用id取的元素

1
.getElementById

.addEventListener

who: form
when: 按下submit的時候
what: 做function

1
form.addEventListener("submit", function (e) {}

設定submit

可以檢測submit是不是正常work。

1
2
3
4
5
6
7
8
9
10
11
12
13
// 取得要操作元素的id
const form = document.getElementById("form");
const username = document.getElementById("username");
const email = document.getElementById("email");
const password = document.getElementById("password");
const password2 = document.getElementById("password2");

//Event Listener,監聽submit按鈕。
form.addEventListener("submit", function (e) {
e.preventDefault();
console.log("Hi");
console.log(username); //<input type="text" id="username" placeholder="Enter username">
console.log(username.value); //Phoebe

Simple Validation

透過if…else…簡易判斷

parentElement取得父元素,覆寫成form-control的class。

.className加上這個class的意思。

.className範例

getelementbyid 與 queryselectort 差別?

qeurySelector屬於W3s中的Selectors API的規範。屬於靜態static node。

getElementById屬於DOM的規範。屬於動態live node list,會隨著對文檔操作的改變。

參考文章

1
2
3
4
5
6
7
8
const formControl = input.parentElement;
// 增加classname,覆寫form-control class,變成form-control error。
formControl.className = "form-control error";
// 選取到small(顯示錯誤的文字)
const small = formControl.querySelector("small");
//將不同的function string填入
small.innerText = message;
}
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
const form = document.getElementById("form");
const username = document.getElementById("username");
const email = document.getElementById("email");
const password = document.getElementById("password");
const password2 = document.getElementById("password2");

//Show Input Error message 顯示錯誤的框
//input指EventListener取得的值
function showError(input, message) {
// 取得父元素(parenetElement就是form-control)
const formControl = input.parentElement;
// 增加classname,覆寫form-control class,變成form-control error。
formControl.className = "form-control error";
// 選取到small(顯示錯誤的文字)
const small = formControl.querySelector("small");
//將不同的function string填入
small.innerText = message;
}

//Show success outline 顯示成功的框
function showSuccess(input) {
const formControl = input.parentElement;
// 增加classname,覆寫form-control,變成form-control success。
formControl.className = "form-control success";
}

//Check email is valid
function isValidEmail(email) {
const re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(String(email).toLowerCase());
}

//Event Listener事件監聽
form.addEventListener("submit", function (e) {
// 防止送出時跳掉
e.preventDefault();
if (username.value === "") {
showError(username, "Usrename is required");
} else {
showSuccess(username);
}

if (email.value === "") {
showError(email, "Email is required");
} else if (!isValidEmail(email.value)) {
showError(email, "Email is not valid");
} else {
showSuccess(email);
}

if (password.value === "") {
showError(password, "Password is required");
} else {
showSuccess(password);
}

if (password2.value === "") {
showError(password2, "Password 2 is required");
} else {
showSuccess(password2);
}
});

Check Required & Refactor

原本程式太多判斷式,使用functiont重構和ES6語法優化。

甚麼是Refactor?

中文為”代碼重構”,指對程式做任何更動以增加可讀性或者簡化結構,但不影響輸出結果。

講解如何使用checkRequired

1
2
3
4
5
6
7
8
9
form.addEventListener("submit", function (e) {
e.preventDefault();
checkRequired([username, email, password, password2]);
});

function checkRequired(inputArr) {
inputArr.forEach(function (input) {
console.log(input.value);
});

在checkRequire加上判斷式顯示正確或錯誤

charAt(0)回傳遞第零個值。

slice([begin,end])方法會回傳一個新陣列物件,為陣列選擇 begin 至 end。

1
2
3
4
function getFieldName(input) {
//轉換成大寫。加上後面的字母。
return input.id.charAt(0).toUpperCase() + input.id.slice(1);
}

ES6語法‵‵${} 錢字號可以帶入變數。

1
showError(input, `${getFieldName(input)} is required`);
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
form.addEventListener("submit", function (e) {
e.preventDefault();
checkRequired([username, email, password, password2]);
});

//Check requires fields
function checkRequired(inputArr) {
// 使用array的方法,再用foreach去讀取每個元素(username,email...)
// trim()將字串去除空白
inputArr.forEach(function (input) {
if (input.value.trim() === "") {
//可以取得username,email,password,password2
//console.log(input.id);
// 增加function getFieldName
showError(input, `${getFieldName(input)} is required`);
} else {
showSuccess(input);
}
});
}

// Get fieldname
function getFieldName(input) {
// charAt(0).toUpperCase()只回傳第零個元素,轉換成大寫。加上後面的字母。
return input.id.charAt(0).toUpperCase() + input.id.slice(1);
}

Check Length, Email & Password Match 完成

增加的功能

  1. checkLength
  2. 優化isValidEmail
  3. checkPasswordMatch
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
const form = document.getElementById("form");
const username = document.getElementById("username");
const email = document.getElementById("email");
const password = document.getElementById("password");
const password2 = document.getElementById("password2");

//Show Input Error message
function showError(input, message) {
// 取得父元素
const formControl = input.parentElement;
// 增加classname,覆寫form-control class,變成
formControl.className = "form-control error";
// 選取到small
const small = formControl.querySelector("small");
//將不同的function string填入
small.innerText = message;
}

//Show success outline
function showSuccess(input) {
const formControl = input.parentElement;
// 增加classname,覆寫form-control,變成form-control success。
formControl.className = "form-control success";
}

//Check email is valid
function isValidEmail(input) {
const re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
if (re.test(input.value.trim())) {
showSuccess(input);
} else {
showError(input, "Email is not valid");
}
}

//Check requires fields
function checkRequired(inputArr) {
inputArr.forEach(function (input) {
if (input.value.trim() === "") {
//console.log(input.id); //可以取得username,email,password,password2
// 增加function getFieldName
showError(input, `${getFieldName(input)} is required`);
} else {
showSuccess(input);
}
});
}

//Check input length
function checkLength(input, min, max) {
if (input.value.length < min) {
showError(
input,
`${getFieldName(input)} must be at least ${min} characters`
);
} else if (input.value.length > max) {
showError(
input,
`${getFieldName(input)} must be less than ${max} characters`
);
} else {
showSuccess(input);
}
}

// Check password match
function checkPasswordMatch(input1, input2) {
if (input1.value !== input2.value) {
showError(input2, "Passwords do not match");
}
}
// Get fieldname
function getFieldName(input) {
// 第零個元素,轉換成大寫,加上後面的字母
return input.id.charAt(0).toUpperCase() + input.id.slice(1);
}

//Event Listener
form.addEventListener("submit", function (e) {
e.preventDefault();

checkRequired([username, email, password, password2]);
// (username,min,max)
checkLength(username, 3, 15);
checkLength(password, 6, 25);
isValidEmail(email);
checkPasswordMatch(password, password2);
});

遇到的問題

一開始開發者工具會一直跳出這個錯誤

解決辦法


[實作] 表單驗證
https://phoebeho.com/Portfolio/20210116/2976928005/
作者
Phoebe
發布於
2021年1月16日
許可協議