【vue3】黑馬程序員前端Vue3小兔鮮電商項目【八】

黑馬程序員前端Vue3小兔鮮電商項目【八】登錄頁面

image-20230624165512735

登錄頁面的主要功能就是表單校驗和登錄登出業務。

賬號密碼

accountpassword
cdshi0080123456
cdshi0081123456
cdshi0082123456
cdshi0083123456
cdshi0084123456
cdshi0085123456
cdshi0086123456
cdshi0087123456
cdshi0088123456

路由配置

模版代碼

在 src\views\Login\index.vue 中添加登錄頁代碼:

<script setup></script><template><div><header class="login-header"><div class="container m-top-20"><h1 class="logo"><RouterLink to="/">小兔鮮</RouterLink></h1><RouterLink class="entry" to="/">進入網站首頁<i class="iconfont icon-angle-right"></i><i class="iconfont icon-angle-right"></i></RouterLink></div></header><section class="login-section"><div class="wrapper"><nav><a href="javascript:;">賬戶登錄</a></nav><div class="account-box"><div class="form"><el-form label-position="right" label-width="60px"status-icon><el-form-item  label="賬戶"><el-input/></el-form-item><el-form-item label="密碼"><el-input/></el-form-item><el-form-item label-width="22px"><el-checkbox  size="large">我已同意隱私條款和服務條款</el-checkbox></el-form-item><el-button size="large" class="subBtn">點擊登錄</el-button></el-form></div></div></div></section><footer class="login-footer"><div class="container"><p><a href="javascript:;">關于我們</a><a href="javascript:;">幫助中心</a><a href="javascript:;">售后服務</a><a href="javascript:;">配送與驗收</a><a href="javascript:;">商務合作</a><a href="javascript:;">搜索推薦</a><a href="javascript:;">友情鏈接</a></p><p>CopyRight &copy; 小兔鮮兒</p></div></footer></div>
</template><style scoped lang='scss'>
.login-header {background: #fff;border-bottom: 1px solid #e4e4e4;.container {display: flex;align-items: flex-end;justify-content: space-between;}.logo {width: 200px;a {display: block;height: 132px;width: 100%;text-indent: -9999px;background: url("@/assets/images/logo.png") no-repeat center 18px / contain;}}.sub {flex: 1;font-size: 24px;font-weight: normal;margin-bottom: 38px;margin-left: 20px;color: #666;}.entry {width: 120px;margin-bottom: 38px;font-size: 16px;i {font-size: 14px;color: $xtxColor;letter-spacing: -5px;}}
}.login-section {background: url('@/assets/images/login-bg.png') no-repeat center / cover;height: 488px;position: relative;.wrapper {width: 380px;background: #fff;position: absolute;left: 50%;top: 54px;transform: translate3d(100px, 0, 0);box-shadow: 0 0 10px rgba(0, 0, 0, 0.15);nav {font-size: 14px;height: 55px;margin-bottom: 20px;border-bottom: 1px solid #f5f5f5;display: flex;padding: 0 40px;text-align: right;align-items: center;a {flex: 1;line-height: 1;display: inline-block;font-size: 18px;position: relative;text-align: center;}}}
}.login-footer {padding: 30px 0 50px;background: #fff;p {text-align: center;color: #999;padding-top: 20px;a {line-height: 1;padding: 0 10px;color: #999;display: inline-block;~a {border-left: 1px solid #ccc;}}}
}.account-box {.toggle {padding: 15px 40px;text-align: right;a {color: $xtxColor;i {font-size: 14px;}}}.form {padding: 0 20px 20px 20px;&-item {margin-bottom: 28px;.input {position: relative;height: 36px;>i {width: 34px;height: 34px;background: #cfcdcd;color: #fff;position: absolute;left: 1px;top: 1px;text-align: center;line-height: 34px;font-size: 18px;}input {padding-left: 44px;border: 1px solid #cfcdcd;height: 36px;line-height: 36px;width: 100%;&.error {border-color: $priceColor;}&.active,&:focus {border-color: $xtxColor;}}.code {position: absolute;right: 1px;top: 1px;text-align: center;line-height: 34px;font-size: 14px;background: #f5f5f5;color: #666;width: 90px;height: 34px;cursor: pointer;}}>.error {position: absolute;font-size: 12px;line-height: 28px;color: $priceColor;i {font-size: 14px;margin-right: 2px;}}}.agree {a {color: #069;}}.btn {display: block;width: 100%;height: 40px;color: #fff;text-align: center;line-height: 40px;background: $xtxColor;&.disabled {background: #cfcdcd;}}}.action {padding: 20px 40px;display: flex;justify-content: space-between;align-items: center;.url {a {color: #999;margin-left: 10px;}}}
}.subBtn {background: $xtxColor;width: 100%;color: #fff;
}
</style>
配置路由跳轉

修改 src\views\Layout\components\LayoutNav.vue 文件中【請先登錄】的 a 標簽:

 <li><a href="javascript:;" @click="router.push('/login')">請先登錄</a></li>

表單校驗實現

作用:前端提前校驗可以省去一些錯誤的請求提交,為后端節省接口壓力。

ElementPlus 表單組件內置了表單校驗功能,只需要按照組件要求配置必要參數即可(直接看文檔)。ElementPlus表單組件內置了初始的校驗配置,應付簡單的校驗只需要通過配置即可,如果想要定制一些特殊的校驗需求,可以使用自定義校驗規則。

校驗要求

用戶名:不能為空,字段名為 account
密碼:不能為空且為6-14個字符,字段名為 password
同意協議:必選,字段名為 agree

代碼實現
  1. 按照字段準備表單對象:

    // 1.準備表單對象
    const form = ref({account: '',password: '',agree: true
    })
  2. 按照產品要求準備規則對象:

    // 2. 校驗規則對象
    const rules = {account: [{ required: true, message: '用戶名不能為空', trigger: 'blur' }],password: [{ required: true, message: '密碼不能為空', trigger: 'blur' },{ min: 6, max: 24, message: '密碼長度要求6-14個字符', trigger: 'blur' }],agree: [{validator: (rule, value, callBack) => {console.log(value)//自定義校驗邏輯// 勾選協議通過,不勾選不通過if (value) {callBack()} else {callBack(new Error('請勾選協議'))}}}]
    }
  3. 給表單綁定用戶表單對象和校驗規則:

    <el-form label-position="right" :model="form" :rules="rules" label-width="60px" status-icon>...
    </el-form>
  4. 指定表單域的校驗字段名:

    <el-form-item prop="account" label="賬戶"><el-input />
    </el-form-item>
    <el-form-item prop="password" label="密碼"><el-input />
    </el-form-item>
    <el-form-item prop="agree" label-width="22px"><el-checkbox size="large">我已同意隱私條款和服務條款</el-checkbox>
    </el-form-item>
  5. 把表單對象進行雙向綁定:

<el-form-item prop="account" label="賬戶"><el-input v-model="form.account"/>
</el-form-item>
<el-form-item prop="password" label="密碼"><el-input v-model="form.password"/>
</el-form-item>
<el-form-item prop="agree" label-width="22px"><el-checkbox size="large" v-model="form.agree">我已同意隱私條款和服務條款</el-checkbox>
</el-form-item>
統一校驗

在點擊登錄時需要對所有需要校驗的表單進行統一校驗。

  1. 獲取表單實例:

    // 3.獲取 form 實例做統一校驗
    const formRef = ref(null)

    與表單進行綁定:

    <el-form ref="formRef" label-position="right" :model="form" :rules="rules" label-width="60px" status-icon>...
    </el-form>
  2. 編寫登錄邏輯:

    const doLogin = () => {// 調用實例方法formRef.value.validate(async (valid) => {// valid: 所有表單都通過校驗  才為trueconsole.log(valid)// 以valid做為判斷條件 如果通過校驗才執行登錄邏輯if (valid) {// TODO LOGIN}})
    }
  3. 與登錄按鈕進行綁定:

     <el-button size="large" class="subBtn" @click="doLogin">點擊登錄</el-button>

登錄基礎業務實現

基礎思想

  1. 調用登錄接口獲取用戶信息
  2. 提示用戶當前是否成功
  3. 跳轉到首頁
  1. 新建 src\apis\user.js 文件,編寫登錄 api:

    //封裝所有和用戶相關的接口函數
    import http from '@/utils/http'export const loginApi = ({ account, password }) => {return http({url: '/login',method: 'POST',data: {account, password}})
    }
  2. src\views\Login\index.vue 中完善登錄邏輯:

    // 3.獲取 form 實例做統一校驗
    const router = useRouter()
    const formRef = ref(null)
    const doLogin = () => {const { account, password } = form.value// 調用實例方法formRef.value.validate(async (valid) => {// valid: 所有表單都通過校驗  才為trueconsole.log(valid)// 以valid做為判斷條件 如果通過校驗才執行登錄邏輯if (valid) {// TODO LOGINawait loginAPI({ account, password })// 1. 提示用戶ElMessage({ type: 'success', message: '登錄成功' })// 2. 跳轉首頁router.replace({ path: '/' })}})
    }

統一錯誤信息提示

在 src\utils\http.js 中的響應攔截器中進行處理:

// axios響應式攔截器
http.interceptors.response.use(res => res.data, e => {// 統一錯誤提示ElMessage({type: 'warning',message: e.response.data.message})return Promise.reject(e)
})

Pinia 管理用戶數據

由于用戶數據的特殊性,在很多組件中都有可能進行共享,共享的數據使用 Pinia 管理會更加方便。Pinia 負責用戶數據相關的 state 和 action,組件中只負責觸發 action 函數并傳遞參數。

  1. 添加 src\stores\user.js 文件,在其中添加保存用戶數據的方法:

    // 管理用戶數據相關
    import { defineStore } from 'pinia'
    import { ref } from 'vue'
    import { loginAPI } from '@/apis/user'export const useUserStore = defineStore('user', () => {// 1. 定義管理用戶數據的stateconst userInfo = ref({})// 2. 定義獲取接口數據的action函數const getUserInfo = async ({ account, password }) => {const res = await loginAPI({ account, password })userInfo.value = res.result}// 3. 以對象的格式把state和action returnreturn {userInfo,getUserInfo}
    })
  2. 替換 src\views\Login\index.vue 中登錄邏輯的原代碼:

    import {useUserStore} from '@/stores/user'
    ...
    const userStore =  useUserStore()
    // TODO LOGIN
    await userStore.getUserInfo({ account, password })

Pinia 用戶數據持久化

用戶數據中有一個關鍵的數據叫做 Token(用來標識當前用戶是否登錄),而 Token 持續一段時間才會過期。Pinia 的存儲是基于內存的,刷新就丟失,為了保持登錄狀態就要做到刷新不丟失,需要配合持久化進行存儲。

最終效果:操作 state 時會自動把用戶數據在本地的 localStorage 也存一份,刷新的時候會從 localStorage 中先取。

  1. 安裝 pinia 持久化插件 persistedstate:

    npm i pinia-plugin-persistedstate  
  2. 在 main.js 中注冊 pinia 持久化插件:

    import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'const app = createApp(App)
    const pinia = createPinia()
    //注冊持久化插件
    pinia.use(piniaPluginPersistedstate)
    app.use(pinia)
  3. 對 store 持久化配置:

    export const useUserStore = defineStore('user', () => {...
    }, {persist: true
    })

用戶登錄狀態

在首頁根據用戶登錄狀態區分顯示的模塊。

在 src\views\Layout\components\LayoutNav.vue 中獲取 pinia 中存儲的用戶數據:

import { useUserStore } from '@/stores/user'
const userStore = useUserStore()

修改模板的 v-if 判斷邏輯:

<!--多模版渲染區分登錄狀態和非登錄狀態-->
<!--適配思路:登錄時顯示第一塊非登錄時顯示第二塊是否有token-->
<template v-if="userStore.userInfo.token"><li><a href="javascript:;"><i class=" iconfont icon-user"></i>{{userStore.userInfo.account}}</a></li>...
</template>
<template v-else>...
</template>

請求攔截器攜帶 token

Token作為用戶標識,在很多個接口中都需要攜帶Token才可以正確獲取數據,所以需要在接口調用時攜帶Token。另外,為了統一控制采取請求攔截器攜帶的方案。

Axiosi請求攔截器可以在接口正式發起之前對請求參數做一些事情,通常Token數據會被注入到請求header中,格式按
照后端要求的格式進行拼接處理。格式如圖:

image-20230624164604499

修改 src\utils\http.js 文件中的請求攔截器,從 pinia 獲取token數據,將 token 存儲到請求的請求頭中:

// axios請求攔截器
htpp.interceptors.request.use(config => {// 1. 從pinia獲取token數據const userStore = useUserStore()// 2. 按照后端的要求拼接token數據const token = userStore.userInfo.tokenif (token) {config.headers.Authorization = `Bearer ${token}`}return config
}, e => Promise.reject(e))

退出登錄實現

基礎思想:

  1. 清除用戶信息
  2. 跳轉到登錄頁
  1. src\stores\user.js 中新增清除用戶信息方法:

    export const useUserStore = defineStore('user', () => {...// 退出時清除用戶信息const clearUserInfo = () => {userInfo.value = {}}// 3. 以對象的格式把state和action returnreturn {userInfo,getUserInfo,clearUserInfo}
    }, {persist: true
    })
  2. 執行退出邏輯,清除用戶信息:

    <script setup>
    import { useUserStore } from '@/stores/userStore'
    import { useRouter } from 'vue-router'
    const userStore = useUserStore()
    const router = useRouter()
    const confirm = () => {console.log('用戶要退出登錄了')// 退出登錄業務邏輯實現// 1.清除用戶信息 觸發actionuserStore.clearUserInfo()// 2.跳轉到登錄頁router.push('/login')
    }
    </script>

Token 失效攔截處理

Token的有效性可以保持一定時間,如果用戶一段時間不做任何操作,Token.就會失效,使用失效的Token再去請求一
些接口,接口就會報401狀態碼錯誤,需要我們做額外處理。

在 src\utils\http.js 中進行處理:

// axios響應式攔截器
http.interceptors.response.use(res => res.data, e => {// 從pinia獲取token數據const userStore = useUserStore()// 統一錯誤提示ElMessage({type: 'warning',message: e.response.data.message})// 401 token 失效處理// 1.清楚本地用戶數據// 2.跳轉登錄頁if(e.response.status===401){userStore.clearUserInfo()router.push('/login')}return Promise.reject(e)
})

本文轉自 https://blog.csdn.net/qq_20185737/article/details/131363742?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522267ecdbd4b79cab0f88ca091b1719024%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=267ecdbd4b79cab0f88ca091b1719024&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogfirst_rank_ecpm_v1~rank_v31_ecpm-2-131363742-null-null.nonecase&utm_term=%E5%B0%8F%E5%85%94&spm=1018.2226.3001.4450,如有侵權,請聯系刪除。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:
http://www.pswp.cn/pingmian/79471.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/79471.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/79471.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C++學習:六個月從基礎到就業——C++11/14:右值引用與移動語義

C學習&#xff1a;六個月從基礎到就業——C11/14&#xff1a;右值引用與移動語義 本文是我C學習之旅系列的第三十九篇技術文章&#xff0c;也是第三階段"現代C特性"的第一篇&#xff0c;主要介紹C11/14中引入的右值引用和移動語義。查看完整系列目錄了解更多內容。 引…

基于Qlearning強化學習的電梯群控系統高效調度策略matlab仿真

目錄 1.算法仿真效果 2.算法涉及理論知識概要 2.1 Q-learning強化學習原理 2.2 基于Q-learning的電梯群控系統建模 3.MATLAB核心程序 4.完整算法代碼文件獲得 1.算法仿真效果 matlab2022a仿真結果如下&#xff08;完整代碼運行后無水印&#xff09;&#xff1a; 仿真操作…

31.軟件時序控制方式抗干擾

軟件時序控制方式扛干擾 1. 軟件時序控制抗干擾的時間邏輯2. 應用案例 1. 軟件時序控制抗干擾的時間邏輯 &#xff08;1&#xff09;將受軟件控制的功能或軟件檢測到的狀態一一羅列&#xff1b; &#xff08;2&#xff09;將其中的潛在干擾和敏感信號分開&#xff1b; &#x…

Ubuntu環境下使用uWSGI服務器【以flask應用部署為例】

0、前置內容說明 首先要知道WSGI是什么&#xff0c;關于WSGI服務器的介紹看這篇&#xff1a;WSGI&#xff08;Web Server Gateway Interface&#xff09;服務器 由于從Python 3.11開始限制了在系統級 Python 環境中使用 pip 安裝第三方包&#xff0c;以避免與系統包管理器&am…

d3_v7繪制折線圖

<!DOCTYPE html> <html><head><meta charsetutf-8><title>需求</title><script src"https://d3js.org/d3.v7.min.js"></script><style>* {margin: 0;padding: 0;}html, body {width: 100%;height: 100%;displ…

Hotspot分析(1):單細胞轉錄組識別信息基因(和基因模塊)

這一期我們介紹一個常見的&#xff0c;高分文章引用很高的一個單細胞轉錄組分析工具Hotspot&#xff0c;它可針對單細胞轉錄組數據識別有意義基因或者基因module&#xff0c;類似于聚類模塊。所謂的”informative "的基因是那些在給定度量中相鄰的細胞之間以相似的方式表達…

爬蟲準備前工作

1.Pycham的下載 網址&#xff1a;PyCharm: The only Python IDE you need 2.Python的下載 網址&#xff1a;python.org&#xff08;python3.9版本之后都可以&#xff09; 3.node.js的下載 網址&#xff1a;Node.js — 在任何地方運行 JavaScript&#xff08;版本使用18就可…

基于Springboot旅游網站系統【附源碼】

基于Springboot旅游網站系統 效果如下&#xff1a; 系統登陸頁面 系統主頁面 景點信息推薦頁面 路線詳情頁面 景點詳情頁面 確認下單頁面 景點信息管理頁面 旅游路線管理頁面 研究背景 隨著互聯網技術普及與在線旅游消費習慣的深化&#xff0c;傳統旅游服務模式面臨效率低、…

利用KMP找出模式串在目標串中所有匹配位置的起始下標

問題關鍵&#xff1a;完成首次匹配之后需要繼續進行模式匹配。 到這一步后&#xff0c;我們不能直接將j 0然后開始下一輪匹配&#xff0c;因為已經匹配過的部分&#xff08;藍色部分&#xff09;中仍然可能存在與模式串重疊的子串&#xff1a; 解決辦法&#xff1a; 找到藍…

RR(Repeatable Read)級別如何防止幻讀

在 MySQL 數據庫事務隔離級別中&#xff0c;RR&#xff08;可重復讀&#xff09; 通過 MVCC&#xff08;多版本并發控制&#xff09; 和 鎖機制 的組合策略來避免幻讀問題。 一、MVCC機制&#xff1a;快照讀與版本控制 快照讀&#xff08;Snapshot Read&#xff09; 每個事務啟…

Android運行時ART加載類和方法的過程分析

目錄 一,概述 二,ART運行時的入口 一,概述 既然ART運行時執行的都是翻譯DEX字節碼后得到的本地機器指令了&#xff0c;為什么還需要在OAT文件中包含DEX文件&#xff0c;并且將它加載到內存去呢&#xff1f;這是因為ART運行時提供了Java虛擬機接口&#xff0c;而要實現Java虛…

Javase 基礎加強 —— 02 泛型

本系列為筆者學習Javase的課堂筆記&#xff0c;視頻資源為B站黑馬程序員出品的《黑馬程序員JavaAI智能輔助編程全套視頻教程&#xff0c;java零基礎入門到大牛一套通關》&#xff0c;章節分布參考視頻教程&#xff0c;為同樣學習Javase系列課程的同學們提供參考。 01 認識泛型…

Oracle VirtualBox 在 macOS 上的詳細安裝步驟

Oracle VirtualBox 在 macOS 上的詳細安裝步驟 一、準備工作1. 系統要求2. 下載安裝包二、安裝 VirtualBox1. 掛載安裝鏡像2. 運行安裝程序3. 處理安全限制(僅限首次安裝)三、安裝擴展包(增強功能)四、配置第一個虛擬機1. 創建新虛擬機2. 分配內存3. 創建虛擬硬盤4. 加載系…

RAGFlow 接入企業微信應用實現原理剖析與最佳實踐

背景 近期有醫美行業客戶咨詢我們智能客服產品&#xff0c;期望將自己企業的產品、服務以及報價信息以企微應用的方式給到客戶進行體驗互動&#xff0c;提升企業運營效率。關于企業微信對接&#xff0c;我們分享下最佳實踐&#xff0c;拋磚引玉。效果圖如下&#xff1a; 這里也…

【心海資源】子比主題新增注冊與會員用戶展示功能模塊及實現方法

內容改寫&#xff1a; 本次分享的是子比主題頂部展示注冊用戶與會員信息的功能模塊及其實現方式。 你可以通過兩種方式啟用該功能&#xff1a; 直接在后臺進入“外觀 → 小工具”啟用該展示模塊&#xff0c;操作簡便&#xff1b;也可將提供的代碼覆蓋至子比主題目錄中&#…

CSDN積分詳解(介紹、獲取、用途)

&#x1f91f;致敬讀者 &#x1f7e9;感謝閱讀&#x1f7e6;笑口常開&#x1f7ea;生日快樂?早點睡覺 &#x1f4d8;博主相關 &#x1f7e7;博主信息&#x1f7e8;博客首頁&#x1f7eb;專欄推薦&#x1f7e5;活動信息 文章目錄 積分**一、積分類型及用途****二、積分獲取途…

【iview】es6變量結構賦值(對象賦值)

變量的解構賦值 以iview的src/index.js中Vue.prototype.$IVIEW改造為例練習下怎么使用變量的解構賦值 原來的寫法&#xff1a; const install function(Vue, opts {}) {if (install.installed) return;locale.use(opts.locale);locale.i18n(opts.i18n);Object.keys(iview).fo…

【c++深入系列】:萬字詳解vector(附模擬實現的vector源碼)

&#x1f525; 本文專欄&#xff1a;c &#x1f338;作者主頁&#xff1a;努力努力再努力wz &#x1f4aa; 今日博客勵志語錄&#xff1a; 種子破土時從不問‘會不會有光’&#xff0c;它只管生長 ★★★ 本文前置知識&#xff1a; 模版 1.什么是vector 那么想必大家都學過順…

MySQL基礎關鍵_007_DQL 練習

目 錄 一、題目 二、答案&#xff08;不唯一&#xff09; 1.查詢每個部門薪資最高的員工信息 2.查詢每個部門高于平均薪水的員工信息 3. 查詢每個部門平均薪資等級 4.查詢部門中所有員工薪資等級的平均等級 5.不用分組函數 max 查詢最高薪資 6.查詢平均薪資最高的部門編…

Jenkis安裝、配置及賬號權限分配保姆級教程

Jenkis安裝、配置及賬號權限分配保姆級教程 安裝Jenkins下載Jenkins啟動Jenkins配置Jenkins入門Jenkins配置配置中文配置前端自動化任務流新建任務拉取代碼打包上傳云服務并運行配置后端自動化任務流新建任務拉取代碼打包上傳云服務并運行賬號權限分配創建用戶分配視圖權限安裝…