一、初始工作
1、創建登錄文件
在src/views中創建文件LoginView.vue文件
2、創建路由
在router/index.js中增加登錄的信息
代碼
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
const router = createRouter({history: createWebHistory(import.meta.env.BASE_URL),routes: [//將子項全部存入一個大的路由中layout/index.vue,頁面剛進入時調用的時layout/index.vue,在為導航條,默認顯示頁面/home的內容{path: '/',name: 'main',component: () => import('@/layout/index.vue'),children: [{path: '/home',name: 'home',component: HomeView,},{path: '/about',name: 'about',component: () => import('../views/AboutView.vue'),},]},//登錄{path: '/login',name: 'login',component: () => import('@/views/LoginView.vue'),meta: {title: '登錄'}},//404{path: '/:pathMatch(.*)*',name: 'not-found',component: () => import('@/views/NotFoundView.vue'),meta: {title: '頁面未找到'}},],
})
export default router
二、搭建登錄頁面
1、實現效果
2、組件
LoginView.vue
實現底色為紫色,中間為白色卡片的登錄效果,白色卡片左側為圖片效果,右側為表單登錄組件
<template><div class="page_all flex flex-center"><div class="login_all flex flex-between"><div class="login_left flex flex-center"><img src="/svg/login.png"></div><div class="login_right flex flex-center flex-column"><div class="form flex flex-center flex-column"><div class="title flex flex-center">CMS管理系統</div><el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" class="el-form demo-ruleForm":size="formSize" status-icon><el-form-item prop="username"><el-input v-model="ruleForm.username" placeholder="請輸入賬號" /></el-form-item><el-form-item prop="password"><el-input v-model="ruleForm.password" show-password placeholder="請輸入密碼" /></el-form-item><el-form-item class="btn-group"><el-button type="primary" @click="submitForm(ruleFormRef)">登錄</el-button><el-button @click="resetForm(ruleFormRef)">重置</el-button></el-form-item></el-form></div></div></div></div>
</template>
代碼解析?
表單實現?
參考路徑:Form 表單 | Element Plus
①.?<el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" class="el-form demo-ruleForm" :size="formSize" status-icon>
-
ref="ruleFormRef"
:
給表單組件設置一個引用名?ruleFormRef
,方便在 Vue 組件中通過?this.$refs.ruleFormRef
?訪問表單實例。 -
?
:model="ruleForm"
:
將表單數據綁定到?ruleForm
?對象,ruleForm
?是一個 Vue 組件的 data 屬性,通常用于存儲表單字段的值。 -
?
:rules="rules"
:
綁定表單驗證規則,rules
?是一個 Vue 組件的 data 屬性,定義了表單字段的驗證邏輯。 -
?
class="el-form demo-ruleForm"
:
給表單添加 CSS 類名,用于樣式控制。 -
?
:size="formSize"
:
動態設置表單的尺寸(如?large
、medium
、small
),formSize
?是一個 Vue 組件的 data 屬性。 -
?
status-icon
:
在表單驗證時顯示驗證狀態圖標(如成功、失敗)。
②.?<el-form-item prop="username">
-
?**
prop="username"
**:
指定該表單項綁定的字段名?username
,用于表單驗證和數據綁定。
③.?<el-input v-model="ruleForm.username" placeholder="請輸入賬號" />
-
?**
v-model="ruleForm.username"
**:
將輸入框的值雙向綁定到?ruleForm.username
,用戶輸入的內容會實時更新到?ruleForm.username
。 -
?**
placeholder="請輸入賬號"
**:
設置輸入框的占位符文本,提示用戶輸入賬號。
④.?<el-form-item prop="password">
-
?**
prop="password"
**:
指定該表單項綁定的字段名?password
,用于表單驗證和數據綁定。
⑤.?<el-input v-model="ruleForm.password" show-password placeholder="請輸入密碼" />
-
?**
v-model="ruleForm.password"
**:
將輸入框的值雙向綁定到?ruleForm.password
,用戶輸入的內容會實時更新到?ruleForm.password
。 -
?**
show-password
**:
啟用密碼顯示/隱藏切換功能,用戶可以通過點擊圖標切換密碼的可見性。 -
?**
placeholder="請輸入密碼"
**:
設置輸入框的占位符文本,提示用戶輸入密碼。
⑥.?<el-form-item class="btn-group">
-
?**
class="btn-group"
**:
給表單項添加 CSS 類名,用于樣式控制。
⑦.?<el-button type="primary" @click="submitForm(ruleFormRef)">登錄</el-button>
-
?**
type="primary"
**:
設置按鈕的類型為“主按鈕”,通常顯示為藍色。 -
?**
@click="submitForm(ruleFormRef)"
**:
點擊事件,調用?submitForm
?方法并傳入表單實例?ruleFormRef
,用于提交表單。
⑧.?<el-button @click="resetForm(ruleFormRef)">重置</el-button>
-
?**
@click="resetForm(ruleFormRef)"
**:
點擊事件,調用?resetForm
?方法并傳入表單實例?ruleFormRef
,用于重置表單。
⑨.?</el-form>
-
關閉表單組件。
3、樣式
①LoginView.vue - css
大體使用flex布局實現
<style>
.page_all {width: 100%;height: 100vh;background-color: #808cdd;
}.login_all {width: 50%;height: 60%;background-color: white;
}.login_left {width: 50%;height: 98%;
}.login_left img {width: 95%;height: 80%;object-fit: contain;
}.login_right {width: 50%;height: 100%;
}.title {font-size: 25px;color: #646cff;letter-spacing: 3px;height: 20%;
}.form {flex: 1;width: 90%;
}.el-form {width: 60%;
}.el-input__inner {font-size: 12px;
}.btn-group {width: 100%;margin-top: 30px;
}.btn-group button {width: 45%;
}.el-form-item__content {justify-content: space-between;
}
</style>
②base.css
修改主體顏色
/* color palette from <https://github.com/vuejs/theme> */
:root {--vt-c-white: #ffffff;--vt-c-white-soft: #f8f8f8;--vt-c-white-mute: #f2f2f2;--vt-c-black: #181818;--vt-c-black-soft: #222222;--vt-c-black-mute: #282828;--vt-c-indigo: #2c3e50;--vt-c-divider-light-1: rgba(60, 60, 60, 0.29);--vt-c-divider-light-2: rgba(60, 60, 60, 0.12);--vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);--vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);--vt-c-text-light-1: var(--vt-c-indigo);--vt-c-text-light-2: rgba(60, 60, 60, 0.66);--vt-c-text-dark-1: var(--vt-c-white);--vt-c-text-dark-2: rgba(235, 235, 235, 0.64);--el-color-primary: #646cff;--el-button-hover-bg-color: #868bf7;--el-color-primary-light-3: #868bf7;--el-color-primary-light-5:#b4b7ef;--el-color-primary-light-9:#e5e6f7;--el-color-primary-light-7:#c6c8fa;
}
③main.js?
@import './base.css';.flex {display: flex;
}.flex-between {justify-content: space-between;align-items: center;
}.flex-around {justify-content: space-around;align-items: center;
}.flex-center {justify-content: center;align-items: center;
}.flex-column {flex-direction: column;
}
三、js功能實現
1、引入方法
import { reactive, ref } from 'vue' //引入vue響應式
import { login } from '@/api/logininfo' //引入登錄接口
import { useRouter } from 'vue-router' //引入路由
import { ElMessage } from 'element-plus' //引入提示框
import { setToken } from '@/utils/token' //引入token設置
2、設置基本表單數據
//設置表單大小
const formSize = ref('default')
//設置表單數據
const ruleFormRef = ref()
const ruleForm = reactive({username: '',//賬號password: '',//密碼
})
3、設置驗證規則
新加的驗證規則可以使用validator也可使用pattern直接使用正則取限制
//設置驗證規則
const rules = reactive({username: [{ required: true, message: '請輸入賬號', trigger: 'blur' },{ min: 3, max: 10, message: '長度請在3-10之間', trigger: 'blur' },],password: [{ required: true, message: '請輸入密碼', trigger: 'blur' },{ min: 6, max: 20, message: '長度請在6-20之間', trigger: 'blur' },{validator: (rule, value, callback) => {const passwordPattern = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]+$/;if (!passwordPattern.test(value)) {callback(new Error('密碼必須包含大寫字母、小寫字母、數字和特殊字符'));} else {callback();}}, trigger: 'blur'},// 或者// {pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]+$/, message: '密碼必須包含大寫字母、小寫字母、數字和特殊字符', trigger: 'blur'}],
})
4、引入路由
//設置路由
const router = useRouter();
5、封裝接口
①新建api接口方法
新建api接口方法,用于管理用戶登錄時需要請求的方法
②方法實現
api/logininfo.js
引入request中的post和get方法,封裝login方法執行登錄的請求
import { post, get } from '@/utils/request'
// 登錄
export function login(data) {return post({url: '/user/login',data})
}
6、表單提交
提交表單:
發送登錄請求
- 請求成功->提示成功消息->請求成功會返回一個token值,將這個token值存入本地緩存->跳轉到主頁面
- 請求失敗->提示失敗消息
//表單提交
const submitForm = async (formEl) => {if (!formEl) returnawait formEl.validate((valid, fields) => {if (valid) {console.log('submit!');// 1、請求登錄接口進行登錄// 參數為ruleFormconsole.log(ruleForm)// 2、請求登錄接口進行登錄login( ruleForm ).then(res => {console.log('res:', res)if (res.code == 1) {// 3、提示成功信息ElMessage.success(res.msg || '登錄成功')//存入該賬號的tokensetToken(res.data.token)// 4、跳轉頁面router.push('/')}else {ElMessage.error(res.msg || '登錄失敗')}})} else {console.log('error submit!', fields)}})
}
7、重置表單
//重置表單
const resetForm = (formEl) => {if (!formEl) returnformEl.resetFields()
}
注:這里使用的request.js的請求方法是拼接方法
export const get = (obj) => {obj.method = 'GET'if (obj.data) {obj.url += '?' + Object.keys(obj.data).map(key => key + '=' + obj.data[key]).join('&')}return request(obj)
}
export const post = (obj) => {obj.method = 'POST'return request(obj)
}
四、接口實現
1、建立新接口
建立接口/user/login
設置請求參數username和password
2、設置期望?
登錄成功
登錄失敗
五、測試是否成功
1、頁面樣式
2、測試文本框
①登錄文本框
必填測試
長度測試
②密碼文本框
必填測試
長度測試
規范測試
③登錄失敗
根據apifox設置的期望,輸入賬號不等于test時,登錄失敗
④登錄成功
在登錄前查看本地緩存
登錄成功后頁面跳轉,本地緩存中存入返回的token
六、完整代碼
1、LoginView.vue
<template><div class="page_all flex flex-center"><div class="login_all flex flex-between"><div class="login_left flex flex-center"><img src="/svg/login.png"></div><div class="login_right flex flex-center flex-column"><div class="form flex flex-center flex-column"><div class="title flex flex-center">CMS管理系統</div><el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" class="el-form demo-ruleForm":size="formSize" status-icon><el-form-item prop="username"><el-input v-model="ruleForm.username" placeholder="請輸入賬號" /></el-form-item><el-form-item prop="password"><el-input v-model="ruleForm.password" show-password placeholder="請輸入密碼" /></el-form-item><el-form-item class="btn-group"><el-button type="primary" @click="submitForm(ruleFormRef)">登錄</el-button><el-button @click="resetForm(ruleFormRef)">重置</el-button></el-form-item></el-form></div></div></div></div>
</template>
<script setup>
//引入方法
import { reactive, ref } from 'vue' //引入vue響應式
import { login } from '@/api/logininfo' //引入登錄接口
import { useRouter } from 'vue-router' //引入路由
import { ElMessage } from 'element-plus' //引入提示框
import { setToken } from '@/utils/token' //引入token設置//設置表單大小
const formSize = ref('default')
//設置表單數據
const ruleFormRef = ref()
const ruleForm = reactive({username: '',password: '',
})//設置路由
const router = useRouter();
//設置驗證規則
const rules = reactive({username: [{ required: true, message: '請輸入賬號', trigger: 'blur' },{ min: 3, max: 10, message: '長度請在3-10之間', trigger: 'blur' },],password: [{ required: true, message: '請輸入密碼', trigger: 'blur' },{ min: 6, max: 20, message: '長度請在6-20之間', trigger: 'blur' },{validator: (rule, value, callback) => {const passwordPattern = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]+$/;if (!passwordPattern.test(value)) {callback(new Error('密碼必須包含大寫字母、小寫字母、數字和特殊字符'));} else {callback();}}, trigger: 'blur'},// 或者// {pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]+$/, message: '密碼必須包含大寫字母、小寫字母、數字和特殊字符', trigger: 'blur'}],
})//表單提交
const submitForm = async (formEl) => {if (!formEl) returnawait formEl.validate((valid, fields) => {if (valid) {console.log('submit!');// 1、請求登錄接口進行登錄// 參數為ruleFormconsole.log(ruleForm)// 2、請求登錄接口進行登錄login( ruleForm ).then(res => {console.log('res:', res)if (res.code == 1) {// 3、提示成功信息ElMessage.success(res.msg || '登錄成功')//存入該賬號的tokensetToken(res.data.token)// 4、跳轉頁面router.push('/')}else {ElMessage.error(res.msg || '登錄失敗')}})} else {console.log('error submit!', fields)}})
}
//重置表單
const resetForm = (formEl) => {if (!formEl) returnformEl.resetFields()
}</script>
<style>
.page_all {width: 100%;height: 100vh;background-color: #808cdd;
}.login_all {width: 50%;height: 60%;background-color: white;
}.login_left {width: 50%;height: 98%;
}.login_left img {width: 95%;height: 80%;object-fit: contain;
}.login_right {width: 50%;height: 100%;
}.title {font-size: 25px;color: #646cff;letter-spacing: 3px;height: 20%;
}.form {flex: 1;width: 90%;
}.el-form {width: 60%;
}.el-input__inner {font-size: 12px;
}.btn-group {width: 100%;margin-top: 30px;
}.btn-group button {width: 45%;
}.el-form-item__content {justify-content: space-between;
}
</style>
2、main.css
@import './base.css';.flex {display: flex;
}.flex-between {/*將彈性容器內的子元素沿主軸 均勻分布,第一個子元素位于主軸起點,最后一個元素位于主軸終點,中間的元素之間等距相等*/justify-content: space-between;align-items: center;
}/* 水平軸上對齊 */
.flex-around {/*項目在主軸上均勻分布,每個項目兩側間距相等,第一個項目和最后一個項目距離容器邊緣的艱苦是其他項目之間間距的一半*/justify-content: space-around;align-items: center;
}.flex-center {justify-content: center;align-items: center;
}
/* 隱藏底部的按鈕 */
.vue-devtools__panel[data-v-e9063f7b]{display: none;
}
.flex-column {flex-direction: column;
}
/* 設置表單寬度 */
.el-form{width:100% !important;
}
3、base.css
/* color palette from <https://github.com/vuejs/theme> */
:root {--vt-c-white: #ffffff;--vt-c-white-soft: #f8f8f8;--vt-c-white-mute: #f2f2f2;--vt-c-black: #181818;--vt-c-black-soft: #222222;--vt-c-black-mute: #282828;--vt-c-indigo: #2c3e50;--vt-c-divider-light-1: rgba(60, 60, 60, 0.29);--vt-c-divider-light-2: rgba(60, 60, 60, 0.12);--vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);--vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);--vt-c-text-light-1: var(--vt-c-indigo);--vt-c-text-light-2: rgba(60, 60, 60, 0.66);--vt-c-text-dark-1: var(--vt-c-white);--vt-c-text-dark-2: rgba(235, 235, 235, 0.64);--el-color-primary: #646cff;--el-button-hover-bg-color: #868bf7;--el-color-primary-light-3: #868bf7;--el-color-primary-light-5:#b4b7ef;--el-color-primary-light-9:#e5e6f7;--el-color-primary-light-7:#c6c8fa;
}/* semantic color variables for this project */
:root {--color-background: var(--vt-c-white);--color-background-soft: var(--vt-c-white-soft);--color-background-mute: var(--vt-c-white-mute);--color-border: var(--vt-c-divider-light-2);--color-border-hover: var(--vt-c-divider-light-1);--color-heading: var(--vt-c-text-light-1);--color-text: var(--vt-c-text-light-1);--section-gap: 160px;
}/*
@media (prefers-color-scheme: dark) {:root {--color-background: var(--vt-c-black);--color-background-soft: var(--vt-c-black-soft);--color-background-mute: var(--vt-c-black-mute);--color-border: var(--vt-c-divider-dark-2);--color-border-hover: var(--vt-c-divider-dark-1);--color-heading: var(--vt-c-text-dark-1);--color-text: var(--vt-c-text-dark-2);}
} *//* *,
*::before,
*::after {box-sizing: border-box;margin: 0;font-weight: normal;
} */body {min-height: 100vh;color: var(--color-text);background: var(--color-background);transition:color 0.5s,background-color 0.5s;line-height: 1.6;font-family:Inter,-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Fira Sans','Droid Sans','Helvetica Neue',sans-serif;font-size: 15px;text-rendering: optimizeLegibility;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;margin: 0;
}