基於Vue3和element-plus實現登錄功能(最終完整版)
先看一下最終要實現的效果:
登錄頁面:
註冊頁面:
(1)引入element-plus組件庫
引入組件庫的方式有好多種,在這裡我就在main.js全局引入瞭.
npm i element-plus -S
main.js中代碼:
import { createApp } from "vue"; //element-plus import ElementPlus from "element-plus"; import "element-plus/dist/index.css"; import App from "./App.vue"; import router from "./router"; import axios from "axios"; import store from "./store"; //創建實例 const app = createApp(App); //全局應用配置 app.config.globalProperties.$axios = axios; app.use(ElementPlus).use(store).use(router).mount("#app");
引入之後自己可以用幾個按鈕測試一下是否引入成功.
(2)登錄及註冊頁面
html部分
views/account/Login.vue
<template> <div id="login"> <div> <div class="form-wrap"> <ul class="menu-tab"> <li :class="{ current: current_menu === item.type }" v-for="item in data.tab_menu" :key="item.type" @click="toggleMenu(item.type)" > {{ item.label }} </li> </ul> <el-form :model="data.form" ref="account_form" :rules="data.form_rules" label-width="80px" > <el-form-item prop="username"> <label class="form-label">用戶名</label> <el-input type="password" v-model="data.form.username" /> </el-form-item> <el-form-item prop="password"> <label class="form-label">密碼</label> <el-input type="password" v-model="data.form.password" /> </el-form-item> <el-form-item v-show="current_menu === 'register'" prop="passwords "> <label class="form-label">確認密碼</label> <el-input type="password" v-model="data.form.passwords" /> </el-form-item> <el-form-item prop="code"> <label class="form-label">驗證碼</label> <el-row :gutter="10"> <el-col :span="14"> <el-input v-model="data.form.code"></el-input> </el-col> <el-col :span="10"> <el-button type="success" class="el-button-block" @click="handleGetCode" >獲取驗證碼</el-button ></el-col > </el-row> </el-form-item> <el-form-item> <el-button type="danger" class="el-button-block" :disabled="data.submit_button_disabled" :loading="data.submit_button_loading" @click="submitForm" >{{ current_menu === "login" ? "登錄" : "註冊" }}</el-button > </el-form-item> </el-form> </div> </div> </div> </template>
js部分
<script> import { reactive, ref, getCurrentInstance, onBeforeUnmount } from "vue"; import { validate_email, validate_password, validate_code, } from "@/utils/validate"; import { GetCode } from "@/api/common"; import { Register, Login } from "@/api/account"; import sha1 from "js-sha1"; //密碼加密 // ErrorHttp export default { setup() { const instance = getCurrentInstance(); const { proxy } = getCurrentInstance(); console.log("instance", instance); // console.log("proxy", proxy); // 用戶名校驗 const validate_name_rules = (rule, value, callback) => { let regEmail = validate_email(value); if (value === "") { callback(new Error("請輸入郵箱")); } else if (!regEmail) { callback(new Error("郵箱格式不正確")); } else { callback(); } }; //獲取驗證碼 const handleGetCode = () => { const username = data.form.username; const password = data.form.password; const passwords = data.form.passwords; //校驗用戶名 if (!validate_email(username)) { proxy.$message({ message: "用戶名不能為空 或 格式不正確", type: "error", }); return false; } //校驗密碼 if (!validate_password(password)) { proxy.$message({ message: "密碼不能為空 或 格式不正確", type: "error", }); return false; } //判斷為註冊時,校驗兩次密碼 if (data.current_menu === "redister" ** (password !== passwords)) { proxy.$message({ message: "兩次密碼不一致", type: "error", }); return false; } //獲取驗證碼接口 const requestData = { username: data.form.username, module: "register", }; data.code_button_loading = true; data.code_button_text = "發送中"; GetCode(requestData) .then((res) => { // console.log("123", res.data);驗證碼 // const data=res.resCode const data = res; if (data.resCode === 1024) { proxy.$message.error(data.message); return false; } // 成功 Elementui 提示 proxy.$message({ message: data.message, type: "success", }); //執行倒計時 countdown(); }) .catch((err) => { console.log(err); data.code_button_loading = false; data.code_button_text = "發送驗證碼"; }); // ErrorHttp(requestData) // .then((res) => { // console.log(res.data); // // const data=res.resCode // const data = res.data; // if (data.resCode === 1024) { // proxy.$message.error(data.message); // return false; // } // // 成功 Elementui 提示 // proxy.$message({ // message: data.message, // type: "success", // }); // //執行倒計時 // countdown(); // }) // .catch((err) => { // console.log(err); // data.code_button_loading = false; // data.code_button_text = "發送驗證碼"; // }); }; /** 倒計時 */ const countdown = (time) => { if (time && typeof time !== "number") { return false; } let second = time || 60; // 默認時間 data.code_button_loading = false; // 取消加載 data.code_button_disabled = true; // 禁用按鈕 data.code_button_text = `倒計進${second}秒`; // 按鈕文本 // 判斷是否存在定時器,存在則先清除 if (data.code_button_timer) { clearInterval(data.code_button_timer); } // 開啟定時器 data.code_button_timer = setInterval(() => { second--; data.code_button_text = `倒計進${second}秒`; // 按鈕文本 if (second <= 0) { data.code_button_text = `重新獲取`; // 按鈕文本 data.code_button_disabled = false; // 啟用按鈕 clearInterval(data.code_button_timer); // 清除倒計時 } }, 1000); }; // 組件銷毀之前 - 生命周期 onBeforeUnmount(() => { clearInterval(data.code_button_timer); // 清除倒計時 }); // 校驗確認密碼 const validate_password_rules = (rule, value, callback) => { let regPassword = validate_password(value); if (value === "") { callback(new Error("請輸入密碼")); } else if (!regPassword) { callback(new Error("請輸入>=6並且<=20位的密碼,包含數字、字母")); } else { callback(); } }; // 校驗確認密碼 const validate_passwords_rules = (rule, value, callback) => { // 如果是登錄,不需要校驗確認密碼,默認通過 if (data.current_menu === "login") { callback(); } let regPassword = validate_password(value); // 獲取“密碼” const passwordValue = data.form.password; if (value === "") { callback(new Error("請輸入密碼")); } else if (!regPassword) { callback(new Error("請輸入>=6並且<=20位的密碼,包含數字、字母")); } else if (passwordValue && passwordValue !== value) { callback(new Error("兩次密碼不一致")); } else { callback(); } }; const validate_code_rules = (rule, value, callback) => { let regCode = validate_code(value); // 激活提交按鈕 data.submit_button_disabled = false; if (value === "") { callback(new Error("請輸入驗證碼")); } else if (!regCode) { callback(new Error("請輸入6位的驗證碼")); } else { callback(); } }; // 提交表單 const submitForm = () => { // let res = proxy.$refs.account_form; proxy.$refs.account_form.validate((valid) => { if (valid) { console.log("提交表單", current_menu.value); current_menu.value === "login" ? login() : register(); // register(); } else { alert("error submit!"); return false; } }); // console.log(" 提交表單", res); }; /** 登錄 */ const login = () => { const requestData = { username: data.form.username, password: sha1(data.form.password), code: data.form.code, }; data.submit_button_loading = true; Login(requestData) .then((response) => { console.log("login", response); data.submit_button_loading = false; proxy.$message({ message: response.message, type: "success", }); reset(); }) .catch((error) => { console.log("登錄失敗", error); data.submit_button_loading = false; }); }; //註冊 const register = () => { const requestData = { username: data.form.username, password: sha1(data.form.password), code: data.form.code, }; data.submit_button_loading = true; Register(requestData) .then((res) => { proxy.$message({ message: res.message, type: "success", }); }) .catch((error) => { console.log("註冊錯誤", error); data.submit_button_loading = false; }); }; /** 重置 */ const reset = () => { // 重置表單 proxy.$refs.form.resetFields(); // 切回登錄模式 data.current_menu = "login"; // 清除定時器 data.code_button_timer && clearInterval(data.code_button_timer); // 獲取驗證碼重置文本 data.code_button_text = "獲取驗證碼"; // 獲取驗證碼激活 data.code_button_disabled = false; // 禁用提交按鈕 data.submit_button_disabled = true; // 取消提交按鈕加載 data.submit_button_loading = false; }; const data = reactive({ form_rules: { username: [{ validator: validate_name_rules, trigger: "change" }], password: [{ validator: validate_password_rules, trigger: "change" }], passwords: [{ validator: validate_passwords_rules, trigger: "change" }], code: [{ validator: validate_code_rules, trigger: "change" }], }, form: { username: "", // 用戶名 password: "", // 密碼 passwords: "", // 確認密碼 code: "", // 驗證碼 }, tab_menu: [ { type: "login", label: "登錄" }, { type: "register", label: "註冊" }, ], /** * 獲取驗證碼按鈕交互 */ code_button_disabled: false, code_button_loading: false, code_button_text: "獲取驗證碼", code_button_timer: null, // 提交按鈕 submit_button_disabled: true, }); const toggleMenu = (type) => { current_menu.value = type; }; let current_menu = ref(data.tab_menu[0].type); // const dataItem = toRefs(data); return { // ...dataItem, data, current_menu, toggleMenu, handleGetCode, submitForm, register, reset, login, }; }, }; </script>
css部分(使用瞭scss)
<style lang="scss" scoped> #login { height: 100vh; background-color: #344a5f; } .form-wrap { width: 320px; padding-top: 100px; margin: auto; } .menu-tab { text-align: center; li { display: inline-block; padding: 10px 24px; margin: 0 10px; color: #fff; font-size: 14px; border-radius: 5px; cursor: pointer; &.current { background-color: rgba(0, 0, 0, 0.1); } } } .form-label { display: block; color: #fff; font-size: 14px; } </style>
(3)封裝一些公共方法及樣式
新建styles文件夾,然後新建幾個樣式文件:
normalize.scss
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ /* Document ========================================================================== */ /** * 1. Correct the line height in all browsers. * 2. Prevent adjustments of font size after orientation changes in iOS. */ /* div的默認樣式不存在padding和margin為0的情況*/ html, body, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, fieldset, form, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { margin: 0; padding: 0; font-size: 100%; font: inherit; vertical-align: baseline; } /* HTML5 display-role reset for older browsers */ article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { display: block; } html { line-height: 1.15; /* 1 */ -webkit-text-size-adjust: 100%; /* 2 */ } /* Sections ========================================================================== */ /** * Remove the margin in all browsers. */ body { margin: 0; font-family: 'Microsoft YaHei'; font-size: 14px; } /** * Render the `main` element consistently in IE. */ main { display: block; } /** * Correct the font size and margin on `h1` elements within `section` and * `article` contexts in Chrome, Firefox, and Safari. */ /* Grouping content ========================================================================== */ /** * 1. Add the correct box sizing in Firefox. * 2. Show the overflow in Edge and IE. */ hr { box-sizing: content-box; /* 1 */ height: 0; /* 1 */ overflow: visible; /* 2 */ } /** * 1. Correct the inheritance and scaling of font size in all browsers. * 2. Correct the odd `em` font sizing in all browsers. */ pre { font-family: monospace, monospace; /* 1 */ font-size: 1em; /* 2 */ } /* Text-level semantics ========================================================================== */ /** * Remove the gray background on active links in IE 10. */ a { background-color: transparent; text-decoration: none; } /** * 1. Remove the bottom border in Chrome 57- * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. */ abbr[title] { border-bottom: none; /* 1 */ text-decoration: underline; /* 2 */ text-decoration: underline dotted; /* 2 */ } /** * Add the correct font weight in Chrome, Edge, and Safari. */ b, strong { font-weight: bolder; } /** * 1. Correct the inheritance and scaling of font size in all browsers. * 2. Correct the odd `em` font sizing in all browsers. */ code, kbd, samp { font-family: monospace, monospace; /* 1 */ font-size: 1em; /* 2 */ } /** * Add the correct font size in all browsers. */ small { font-size: 80%; } /** * Prevent `sub` and `sup` elements from affecting the line height in * all browsers. */ sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; } sub { bottom: -0.25em; } sup { top: -0.5em; } /* Embedded content ========================================================================== */ /** * Remove the border on images inside links in IE 10. */ img { display: block; border-style: none; } /* Forms ========================================================================== */ /** * 1. Change the font styles in all browsers. * 2. Remove the margin in Firefox and Safari. */ button, input, optgroup, select, textarea { font-family: inherit; /* 1 */ font-size: 100%; /* 1 */ margin: 0; /* 2 */ } /** * Show the overflow in IE. * 1. Show the overflow in Edge. */ button, input { /* 1 */ overflow: visible; } /** * Remove the inheritance of text transform in Edge, Firefox, and IE. * 1. Remove the inheritance of text transform in Firefox. */ button, select { /* 1 */ text-transform: none; } /** * Correct the inability to style clickable types in iOS and Safari. */ button, [type="button"], [type="reset"], [type="submit"] { -webkit-appearance: button; } /** * Remove the inner border and padding in Firefox. */ button::-moz-focus-inner, [type="button"]::-moz-focus-inner, [type="reset"]::-moz-focus-inner, [type="submit"]::-moz-focus-inner { border-style: none; padding: 0; } /** * Restore the focus styles unset by the previous rule. */ button:-moz-focusring, [type="button"]:-moz-focusring, [type="reset"]:-moz-focusring, [type="submit"]:-moz-focusring { outline: 1px dotted ButtonText; } /** * Correct the padding in Firefox. */ fieldset { padding: 0.35em 0.75em 0.625em; } /** * 1. Correct the text wrapping in Edge and IE. * 2. Correct the color inheritance from `fieldset` elements in IE. * 3. Remove the padding so developers are not caught out when they zero out * `fieldset` elements in all browsers. */ legend { box-sizing: border-box; /* 1 */ color: inherit; /* 2 */ display: table; /* 1 */ max-width: 100%; /* 1 */ padding: 0; /* 3 */ white-space: normal; /* 1 */ } /** * Add the correct vertical alignment in Chrome, Firefox, and Opera. */ progress { vertical-align: baseline; } /** * Remove the default vertical scrollbar in IE 10+. */ textarea { overflow: auto; } /** * 1. Add the correct box sizing in IE 10. * 2. Remove the padding in IE 10. */ [type="checkbox"], [type="radio"] { box-sizing: border-box; /* 1 */ padding: 0; /* 2 */ } /** * Correct the cursor style of increment and decrement buttons in Chrome. */ [type="number"]::-webkit-inner-spin-button, [type="number"]::-webkit-outer-spin-button { height: auto; } /** * 1. Correct the odd appearance in Chrome and Safari. * 2. Correct the outline style in Safari. */ [type="search"] { -webkit-appearance: textfield; /* 1 */ outline-offset: -2px; /* 2 */ } /** * Remove the inner padding in Chrome and Safari on macOS. */ [type="search"]::-webkit-search-decoration { -webkit-appearance: none; } /** * 1. Correct the inability to style clickable types in iOS and Safari. * 2. Change font properties to `inherit` in Safari. */ ::-webkit-file-upload-button { -webkit-appearance: button; /* 1 */ font: inherit; /* 2 */ } /* Interactive ========================================================================== */ /* * Add the correct display in Edge, IE 10+, and Firefox. */ details { display: block; } /* * Add the correct display in all browsers. */ summary { display: list-item; } /* Misc ========================================================================== */ /** * Add the correct display in IE 10+. */ template { display: none; } /** * Add the correct display in IE 10. */ [hidden] { display: none; } ul, li { list-style: none; }
elementui.scss(當時測試時用的)
.el-button-block{ display: block; width: 100%; }
新建main.scss(引入上方兩個樣式文件)
@import "./normalize.scss"; @import './elementui.scss'
vue.config.js配置一下樣式文件
css: { // 是否使用css分離插件 ExtractTextPlugin extract: true, // 開啟 CSS source maps? sourceMap: false, // css預設器配置項 loaderOptions: { scss: { additionalData: `@import "./src/styles/main.scss";`, }, }, // requireModuleExtension: true, },
登錄中封裝的校驗方法
新建utils文件夾,
a.validate.js
// 校驗郵箱 export function validate_email(value) { let regEmail = /^([a-zA-Z]|[0-9])(\w|\-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/; return regEmail.test(value); } // 校驗密碼 export function validate_password(value) { let regPassword = /^(?!\D+$)(?![^a-zA-Z]+$)\S{6,20}$/; return regPassword.test(value); } // 校驗驗證碼 export function validate_code(value) { let regCode = /^[a-z0-9]{6}$/; return regCode.test(value); }
封裝請求方法
npm i axios -S
記得先在main.js中引入axios
import axios from "axios";
utils中新建request.js
import axios from "axios"; //引入element-plus import { ElMessage } from "element-plus"; console.log("11", process.env.VUE_APP_API); //undefined?? //創建實例 const service = axios.create({ baseURL: "/devApi", //請求地址 timeout: 5000, //超時 }); //添加請求攔截器 service.interceptors.request.use( function (config) { //在發送請求之前做些什麼 return config; }, function (error) { console.log(error.request); const errorData = JSON.parse(error.request.response); if (errorData.message) { //判斷是否具有message屬性 ElMessage({ message: errorData.message, type: "error", }); } //對請求錯誤做些什麼 return Promise.reject(errorData); } ); //添加響 應攔截器 service.interceptors.response.use( function (response) { //對響應數據做些什麼 console.log("響應數據", response); const data = response.data; if (data.resCode === 0) { return Promise.resolve(data); } else { ElMessage({ message: data.message, type: "error", }); return Promise.reject(data); } }, function (error) { //對響應錯誤做些什麼 const errorData = JSON.parse(error.request.response); if (errorData.message) { //判斷是否具有message屬性 ElMessage({ message: errorData.message, type: "error", }); } return Promise.reject(errorData); } ); //暴露service export default service;
(4)配置環境變量
和項目根路徑同級,新建幾個文件:
.env.development
VUE_APP_API = '/devApi'
可以自定義,但是必須是VUE_APP_XXX的格式
.env.production
VUE_APP_API = '/production'
.env.test
VUE_APP_API = '/test'
配置完後記得在axios文件中打印一下,看下能輸出自己配置的環境變量嗎.
(5)配置代理(跨域)
基本大同小異,代理地址改成自己的就可以瞭.
devServer: { open: false, //編譯完成是否自動打開網頁 host: "0.0.0.0", //指定使用地址,默認是localhost,0.0.0.0代表可以被外界訪問 port: 8080, proxy: { "/devApi": { target: "http://v3.web-jshtml.cn/api", //(必選)API服務器的地址 changeOrigin: true, //(必選) 是否允許跨域 ws: false, //(可選) 是否啟用websockets secure: false, //(可選) 是否啟用https接口 pathRewrite: { "^/devApi": "", //匹配開頭為/devApi的字符串,並替換成空字符串 }, }, }, },
登錄基本上是完成瞭,還有優化的點,比如說登錄放在vuex中,這個我先不實現瞭,各位小夥伴覺得還不錯的話,動手點個贊嘍!!!
到此這篇關於基於Vue3和element-plus實現一個完整的登錄功能的文章就介紹到這瞭,更多相關vue3 element-plus登錄內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Vue實現登錄以及登出詳解
- VUE實現註冊與登錄效果
- validate 註冊頁的表單數據校驗實現詳解
- 關於vue-admin-template模板連接後端改造登錄功能
- vue使用rules實現表單字段驗證