Vite Vue (語法糖))驗證碼

這裡用到Math.random js隨機亂數與charAt js 回指定位置的字元 功能

  • 定義verification;綁定驗證碼表單v-model.trim="verification"
  • 驗證碼產生函式參數6碼; 0到9,小寫a-z,大寫A-Z;隨機Math.random();charAt() 方法可傳回指定位置的字元
  • 點擊獲得新的驗證碼函式
  • onMounted即產生=>驗證碼產生函式
github 驗證碼
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
<template>
<div class="item verification">
<!--綁定驗證碼表單-->
<input v-model.trim="verification">
<!--產生的驗證碼-->
<div class="codeBox">{{code_box}}</div>
<!--點擊產生新的驗證碼-->
<i @click="showCode" class="fa-solid fa-arrows-rotate"></i>
</div>
</template>

<script setup lang="ts">
import { ref , onMounted} from 'vue'
const verification = ref<string>('');

// 驗證碼產生
const code_box =ref<string>('');
const generateCode =(length=6)=>{
//0到9,小寫a-z,大寫A-Z
let chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

let code = "";
//隨機亂數Math.random()
//charAt() 方法可傳回指定位置的字元

for (var i = 0; i < length; i++) {
code += chars.charAt(Math.floor(Math.random() * chars.length));
}
code_box.value=code;
}

//點擊獲得新的驗證碼
const showCode =() => {
generateCode();
}

onMounted(() => {
generateCode();
});
</script>

參考資料

Vite Vue 語法糖 element_plus 寫法

@修飾符綁在el-form 上=> @keyup.enter 或是 @keyup.enter.native => el-button 或是 el-input均能使用;
Vue3 Element Plus el-button @keyup.enter Enter按鍵 觸發點擊事件
@修飾符綁在el-button 上=> @keyup.enter 或是 @keyup.enter.native 已測試無任何效果
參考資料
@keyup.enter 與@keyup.enter.native 的差別

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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
<template>
<!--:model 表單綁定 ,ref="formRef" 驗證方式-->
<el-form class="auth-form mb30"
:model="loginForms"
label-width="100px"
label-position="left"
ref="formRef"
@keyup.enter="LoginSubmit(formRef)">
<!--電子郵件 => el-form-item,prop 與:rules必須綁定才能夠驗證-->
<el-form-item
prop="email"
label="電子郵件"
:rules="rulesLogin.email"
>
<!--el-input =>v-mode綁定表單-->
<el-input
v-model.trim="loginForms.email"
:placeholder="請輸入電子郵件"
/>
</el-form-item>
<!--密碼 => el-form-item,prop 與:rules必須綁定才能夠驗證-->
<el-form-item class="password" label="密碼" prop="password" :rules="rulesLogin.password">
<!--el-input =>v-mode綁定表單-->
<el-input
:type="passwordVisible === false ? 'password' : 'input'"
v-model.trim="loginForms.password"
placeholder="請輸入密碼"
/>
<i
@click="passwordVisible = !passwordVisible"
:class="passwordVisible === false ? 'icon-eye-blocked': 'icon-eye'"
>
</i>
</el-form-item>
<!--驗證碼 => el-form-item,prop 與:rules必須綁定才能夠驗證-->
<el-form-item label="驗證碼"
prop="verification"
:rules="rulesLogin.verification">
<el-input v-model.trim="loginForms.verification"/>
<div class="codeBox">{{code_box}}</div>
<a class="btn_change" @click="showCode">
<i class="icon-loop2"></i>
</a>
</el-form-item>
<div class="button_group mb-8">
<el-button class="auth-btn" @click="resetForm(formRef)">
取消
</el-button>
<el-button class="auth-btn" @click="LoginSubmit(formRef)">
送出
</el-button>
</div>
</el-form>
</template>

<script setup lang="ts">
import { ref, computed,onMounted } from "vue"
import { useRouter } from "vue-router"
import { ElMessage } from "element-plus"
import { FormInstance } from "element-plus"

// 定義FormInstance為formRef並在 el-form的ref內使用
const formRef = ref<FormInstance>();
// 表單屬性Type
interface loginFormType{
email: string,
password: string,
verification: string,
}
// Login表單數組
const loginForms = ref<loginFormType>({
// username: '',//admin
email: "",
password: "", //admin
verification: "",
})
// 定義密碼表單顯示text
const passwordVisible = ref(false);
// 定義密碼表單顯示text
const checkPasswordVisible = ref(false)
//登入表單屬性Type
interface rulesLoginType{
email: ({
required: boolean;
message: string;
trigger: string;
type?: undefined;
} | {
type: string;
message: string;
trigger: string[];
required?: undefined;
})[];
password: ({
required: boolean;
message: string;
trigger: string;
} | {
min: number;
max: number;
message: string;
trigger: string;
required?: undefined;
})[];
verification: ({
required: boolean;
message: string;
trigger: string;
validator?: undefined;
} | {
validator: (_rule: object, value: string, callback: Function) => void;
trigger: string;
required?: undefined;
message?: undefined;
})[]
}

//登入表單驗證
const rulesLogin =ref<rulesLoginType>(
{
account: [
{required: true,message : '帳號不能為空',trigger : 'blur'},
{ min: 2, max: 30, message: '帳號在2~30字符之間', trigger: "blur" },
],
password : [
{ required: true, message: '密碼不能為空', trigger: "blur" },
{ min: 2, max: 30, message: '密碼必須在2~30字符之間', trigger: "blur" },
],
verification:[
{ required: true, message: '驗證碼不能為空!', trigger: "blur" },
{ validator: checkVerification, trigger: 'blur' }
],
}
)
// 驗證碼產生
const code_box =ref<string>('');
const generateCode =(length=6)=>{
let chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
let code = "";
for (var i = 0; i < length; i++) {
code += chars.charAt(Math.floor(Math.random() * chars.length));
}
code_box.value=code;
}
//點擊獲得新的驗證碼
const showCode =() => {
generateCode();
}
//驗證碼驗證
const checkVerification =(_rule: object, value: string, callback: Function)=>{
value !== code_box.value?callback(new Error('驗證碼輸入錯誤')):callback();
}
// 登入
const LoginSubmit = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.validate(async (valid: any) => {
if (valid) {
try {
let query = {
email: loginForms.value.email,
password: loginForms.value.password,
}
const res = await Login(query);
if (res.status === 200) {
localStorage.setItem("token", res.data.token)
ElMessage({
message: "Success!", type: "success",
});
router.push({ name: "Admin", })
}

} catch (err: any) {
console.log(err)
errorMessage.value = err.response.message;
const error = errorMessage.value
switch (error) {
case "用戶不存在":
ElMessage.error(t("forms.userNull"))
break
case "密碼錯誤 !":
ElMessage.error(t("forms.passwordError"))
break
}
}
} else {
return false
}
})
}
// 重置
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
}
onMounted(() => {
generateCode();
})
</script>


<style lang="scss">
.verification{
.el-form-item__content{
display: flex;

.el-input{
width: 65%;
max-width: 65%;
}
.codeBox{
margin-left: 15px;
letter-spacing: 1.8px;
font-size: 14px;
font-weight: bolder;
}
.btn_change{
margin-left: 15px;
font-size: 21px;
font-weight: bolder;
color: #00bcd4;
}

}
}
</style>

參考資料

登入頁改為pinia寫法

安裝 pinia 與引入請參閱
src內新增 store資料夾新增 login.ts

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
99
100
101
102
103
104
105
106
107
108
109
//login.ts
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { useRouter } from "vue-router"
import { ElMessage } from "element-plus"
import { Login } from "../api/user"
import { FormInstance } from "element-plus"
import { loginFormType, rulesLoginType} from "../types/loginType"

export const useLoginStore = defineStore('login', () => {
const router = useRouter()
const formRef = ref<FormInstance>();
// Login表單數據
const loginForms = ref<loginFormType>({
email: "",
password: "", //admin
verification: "",
})
// 定義密碼表單顯示text
const passwordVisible = ref(false)
// 定義密碼表單顯示text
const checkPasswordVisible = ref(false)
// 驗證碼產生
const code_box =ref<string>('');
// 驗證碼驗證
const checkVerification =(_rule: object, value: string, callback: Function)=>{
value !== code_box.value?callback(new Error('驗證碼輸入錯誤')):callback();
}
// Login表單驗證
const rulesLogin = computed<rulesLoginType>(() => ({
email: [
{ required: true, message: '不能為空', trigger: "blur" },
{type: "email",message: '不能為空',trigger: ["blur", "change"]},
],
password: [
{ required: true, message: '不能為空', trigger: "blur" },
{ min: 6, max: 30, message: '不能為空', trigger: "blur" },
],

verification:[
{ required: true, message: '驗證碼不能為空!', trigger: "blur" },
{ validator: checkVerification, trigger: 'blur' }
]
}))
// 產生驗證碼
const generateCode =(length=6)=>{
let chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
let code = "";
for (var i = 0; i < length; i++) {
code += chars.charAt(Math.floor(Math.random() * chars.length));
}
code_box.value=code;
}
// 點擊獲得新的驗證碼
const showCode =() => {
generateCode();
}
const errorMessage = ref<string>('');
// 登入
const LoginSubmit = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.validate(async (valid: any) => {
if (valid) {
try {
let query = {
email: loginForms.value.email,
password: loginForms.value.password,
}
const res = await Login(query);
if (res.status === 200) {
localStorage.setItem("token", res.data.token)
ElMessage({
message: "Success!", type: "success",
});
router.push({ name: "Admin", })
}

} catch (err: any) {
console.log(err)
errorMessage.value = err.response.message;
const error = errorMessage.value
switch (error) {
case "用戶不存在":
ElMessage.error('用戶不存在')
break
case "密碼錯誤 !":
ElMessage.error('密碼錯誤 !')
break
}
}
} else {
return false
}
})
}
// 重置
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
}
return {
formRef,
loginForms,passwordVisible,checkPasswordVisible,rulesLogin,
code_box,
generateCode,showCode,
errorMessage,
LoginSubmit,resetForm,
}
})

頁面使用
@修飾符綁在el-form 上=> @keyup.enter 或是 @keyup.enter.native => el-button 或是 el-input均能使用;
Vue3 Element Plus el-button @keyup.enter Enter按鍵 觸發點擊事件
@修飾符綁在el-button 上=> @keyup.enter 或是 @keyup.enter.native 已測試無任何效果
參考資料
@keyup.enter 與@keyup.enter.native 的差別

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
<template>
<!--:model 表單綁定 ,ref="formRef" 驗證方式-->
<el-form class="auth-form mb30"
:model="loginForms"
label-width="100px"
label-position="left"
ref="formRef"
@keyup.enter="LoginSubmit(formRef)"
>
<!--電子郵件 => el-form-item,prop 與:rules必須綁定才能夠驗證-->
<el-form-item
prop="email"
label="電子郵件"
:rules="rulesLogin.email"
>
<!--el-input =>v-mode綁定表單-->
<el-input
v-model.trim="loginForms.email"
:placeholder="請輸入電子郵件"
/>
</el-form-item>
<!--密碼 => el-form-item,prop 與:rules必須綁定才能夠驗證-->
<el-form-item class="password" label="密碼" prop="password" :rules="rulesLogin.password">
<!--el-input =>v-mode綁定表單-->
<el-input
:type="passwordVisible === false ? 'password' : 'input'"
v-model.trim="loginForms.password"
placeholder="請輸入密碼"
/>
<i
@click="passwordVisible = !passwordVisible"
:class="passwordVisible === false ? 'icon-eye-blocked': 'icon-eye'"
>
</i>
</el-form-item>
<!--驗證碼 => el-form-item,prop 與:rules必須綁定才能夠驗證-->
<el-form-item label="驗證碼"
prop="verification"
:rules="rulesLogin.verification">
<el-input v-model.trim="loginForms.verification"/>
<div class="codeBox">{{code_box}}</div>
<a class="btn_change" @click="showCode">
<i class="icon-loop2"></i>
</a>
</el-form-item>
<div class="button_group mb-8">
<el-button class="auth-btn" @click="resetForm(formRef)">
取消
</el-button>
<el-button class="auth-btn" @click="LoginSubmit(formRef)">
送出
</el-button>
</div>
</el-form>
</template>

<script setup lang="ts">
//引入pinia
import {storeToRefs} from 'pinia'
import {onMounted } from "vue"
import { useLoginStore } from '../stores/login'
import {validatorMessageType}from "../types/loginType"
//宣告storeLogin
const storeLogin = useLoginStore();
//解構
const {formRef,loginForms,passwordVisible,checkPasswordVisible,rulesLogin,code_box,errorMessage } = storeToRefs(storeLogin);
const { generateCode,showCode,LoginSubmit,resetForm } = storeLogin;

onMounted(() => {
//頁面打開後即載入驗證碼
generateCode();
})
</script>

github