vue3+ts+axios+pinia實(shí)現(xiàn)無感刷新方式
vue3+ts+axios+pinia實(shí)現(xiàn)無感刷新
1.先在項(xiàng)目中下載aiXos和pinia
npm i pinia --save npm install axios --save
2.封裝axios請(qǐng)求-----
下載js-cookie
npm i JS-cookie -s //引入aixos import type { AxiosRequestConfig, AxiosResponse } from "axios"; import axios from 'axios'; import { ElMessage } from 'element-plus'; import { useUserInfoStore } from '@/stores/modules/UserInfo' import router from '@/router'; import qs from 'qs'; import Cookie from "js-cookie"; let baseURL = ""; // console.log(process.env.NODE_ENV);//判斷環(huán)境 if (process.env.NODE_ENV === 'development') { ? ? baseURL = '/m.api'//后臺(tái)請(qǐng)求接口地址 } else { ? ? baseURL = 'http://xxxx.cn:8080';//這里是項(xiàng)目上線后的地址 ? ? } declare interface TypeResponse extends AxiosResponse { ? ? /** ? ? ?* 錯(cuò)誤號(hào),200表示成功,10006令牌過期 ? ? ?*/ ? ? errno: number, ? ? /** ? ? ?* 返回的信息 ? ? ?*/ ? ? errmsg: string } ? //創(chuàng)建axios實(shí)例 ? const instance = axios.create({ ? ? baseURL, ?// 接口地址 ? ? timeout: 3000, ? ? headers: { ? ? ? ? "Content-Type": 'application/x-www-form-urlencoded' ? ? } ? }); ? ? //添加攔截器 instance.interceptors.request.use((config) => { ? ? // 在發(fā)送請(qǐng)求之前做些什么--給請(qǐng)求頭添加令牌token ? ? (config as any).headers['AdminToken'] = Cookie.get('token')//從cookie中拿token值, //這里是使用了js-cookie插件。 ? ? // console.log(config, "請(qǐng)求攔截器") ? ? return config }, reeor => { ? ? // 對(duì)請(qǐng)求錯(cuò)誤做些什么 ? ? return Promise.reject(reeor); }); // 需要無痛刷新的操作頁面 const METHOD_TYPE = ["_mt=edit", "_mt=create", "_mt=delete"] // //響應(yīng)攔截器 instance.interceptors.response.use(async (response: AxiosResponse) => { ? ? // 對(duì)響應(yīng)數(shù)據(jù)做點(diǎn)什么 ? ? let data = response.data; ? ? let { errno, errmsg } = data; ? ? console.log(response, "響應(yīng)攔截器"); ? ? let path = router.currentRoute.value.fullPath;//當(dāng)前路由路徑 ? ? if (10006 === errno) { ? ? ? ? const configData = response.config.data || '' ? ? ? ? // 判斷請(qǐng)求類型是否需要無痛刷新,index !== -1則需要無痛刷新 ? ? ? ? let index = METHOD_TYPE.findIndex(item => configData.includes(item)) ? ? ? ? if (-1 === index) {//需要重新登入獲取令牌 ? ? ? ? ? ? router.replace({ path: "/login", query: { back: path } })//登入后需要跳回的地址 ? ? ? ? ? ? return ? ? ? ? } else {//需要無痛刷新令牌 ? ? ? ? ? ? const store = useUserInfoStore(); ? ? ? ? ? ? const { username, password } = store.LoginInfo//在狀態(tài)管理里面定義一個(gè)loginInfo ? ? ? ? ? ? // 1.重新獲取令牌 ? ? ? ? ? ? let loginData = { _gp: 'admin', _mt: 'login', username, password }; ? ? ? ? ? ? const { errno, errmsg, data } = await post(loginData)//這里是通過async 將異步序列化改為同步 ? ? ? ? ? ? if (200 == errno) { ? ? ? ? ? ? ? ? Cookie.set('token', data)//保存令牌 ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? router.replace({ path: "/login", query: { back: path } })//登入后需要跳回的地址 ? ? ? ? ? ? ? ? return Promise.reject({ errno, errmsg, data }) ? ? ? ? ? ? } ? ? ? ? ? ? return instance.request(response.config) ? ? ? ? } ? ? // ElMessage.error(errmsg);//錯(cuò)誤信息 ? ? } ? ? return data; }, reeor => { ? ? console.log(reeor); ? ? ? return Promise.reject(reeor); }) ? function get(params?: object): Promise<TypeResponse> { ? ? return instance.get('', { params }); }; function post(data: object, params?: object): Promise<TypeResponse> { ? ? return instance.post('', qs.stringify(data), { params }); }; ? ? //暴露實(shí)列 export { ? ? post, get, }
3.qs.stringify(data)是將請(qǐng)求的數(shù)據(jù)轉(zhuǎn)成表單格式,如果不需要直接去掉就可以了;
4.重新登錄后跳轉(zhuǎn)路由需要設(shè)置,不需要可以去掉
5。狀態(tài)管理--數(shù)據(jù)
下載持久化工具
npm install pinia-plugin-persistedstate --s
在main.js中配置持久化
//引入數(shù)據(jù)持久化插件 import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'; const pinia = createPinia() pinia.use(piniaPluginPersistedstate); app.use(pinia)
import { defineStore } from 'pinia' export const useUserInfoStore = defineStore('UserInfo', { ? ? state:() => ({ ? ? ? ? ? ? ? ? LoginInfo:{ ? ? ? ? ? ? username:'', ? ? ? ? ? ? password:'' ? ? ? ? } ? ? ? }), ? ? ? ? ? ? persist:true;//狀態(tài)存儲(chǔ)持久化 })
6.登錄頁面--存儲(chǔ)表單數(shù)據(jù),也就是用戶名和密碼
npm i lodash --s import Cookies from 'js-cookie';//引入cookie import * as _ from 'lodash';//防抖節(jié)流插件 import {post} from '@/util'; import {useUserInfoStore} from '@/stores/modules/UserInfo' ;//用戶信息 import { useRouter,useRoute } from 'vue-router' ;//引入路由 //這里是表單輸入的數(shù)據(jù) const ruleForm = reactive({ ? ? password: '123456', ? ? username: 'admin' }); //請(qǐng)求接口數(shù)據(jù) let data = { ? ? _gp: "admin", ? ? _mt: 'login', ? ? ...ruleForm }; ? let LoginInfo = useUserInfoStore().LoginInfo;//狀態(tài)管理定義的數(shù)據(jù) async function init() { ? ? await post(data).then((res:any) => { ? ? ? ? let { data: token, errno, errmsg } = res ? ? ? ? if (200 === errno) { ? ? ? ? ? ? let time = new Date() //設(shè)置過期時(shí)間 ? ? ? ? ? ? time.setTime(time.getTime() + 1000 * 60 * 30) ? ? ? ? ? ? Cookies.set('token', token, { expires: time }); ? ? ? ? ? ? Object.assign(LoginInfo,ruleForm) ? ? ? ? ? ? if (route.query.back) { //如果存在參數(shù) ? ? ? ? ? ? ?let paths = route.query.back+''//拼接字符串 ? ? ? ? ? ? ?console.log(paths); ? ? ? ? ? ? ?if (paths=='/') { //因?yàn)槲业膆ome是'/',所有需要判斷 ? ? ? ? ? ? ? ? router.replace('/Surface')//跳轉(zhuǎn)至主頁 ? ? ? ? ? ? ? ? return ? ? ? ? ? ? ?}else{ ? ? ? ? ? ? ? ? router.replace(paths)//則跳轉(zhuǎn)至進(jìn)入登錄頁前的路由 ? ? ? ? ? ? ?} ? ? ? ? ? ? ? ? ? ? ? ? ?} else { ? ? ? ? ? ? router.replace('/Surface')//否則跳轉(zhuǎn)至首頁 ? ? ? ? ? ?} ? ? ? ? ? ?? ? ? ? ? } else { ? ? ? ? ? ? ElMessage.error(errmsg) ? ? ? ? } ? ? }).catch((err:any) => { ? ? ? ? ElMessage.error('登錄異常!') ? ? }) ? ? let info = {//用戶信息請(qǐng)求信息接口數(shù)據(jù) ? ? ? ? _gp: "admin", ? ? ? ? _mt: 'info', ? ? } //下面這個(gè)函數(shù)是請(qǐng)求用戶信息的,不需要可以不寫 ? ? await post(info).then((res:any) => { ? ? ? ? let {data} = res ? ? ? ? console.log(data); ? ? ? ? infos(data) ? ? ? }).catch((err:any)=>{ ? ? ? ? ElMessage.error('登錄異常!') ? ? }) } //防抖節(jié)流 const fangdou = _.debounce(init, 1500, { ? ? leading: true, ?// 延長(zhǎng)開始后調(diào)用 ? ? trailing: false ?// 延長(zhǎng)結(jié)束前調(diào)用 }) //移除組件時(shí),取消防抖 onUnmounted(() => { ? ? fangdou.cancel() })
7.main.js設(shè)置路由守衛(wèi)
import Cookie from 'js-cookie' import router from './router'//引入路由 ? //路由守衛(wèi) router.beforeEach(async (to, from ) => { ?? ?let tokent:string|undefined = Cookie.get('token') ?? ?if (!tokent && to.path == '/login') { ?? ??? ?return ?true ?? ?} ?? ?// 沒有登錄,強(qiáng)制跳轉(zhuǎn)登錄頁 ?? ?if (!tokent && to.path !== '/login') { ?? ??? ?router.replace({path:'/login',query:{back:to.path}}); ?? ?} ?? ?// 防止重復(fù)登錄 ?? ?if (tokent && to.path === '/login') { ?? ??? ?return { ?? ??? ??? ?path: from.path ? from.path : '/Surface' ?? ??? ?} ?? ?} ?? ?return true })
大概就是這么多了
vue3無痛刷新(無感刷新)
無痛刷新的原理:當(dāng)token過期后,在響應(yīng)攔截器通過判斷重新進(jìn)行登入請(qǐng)求
實(shí)現(xiàn)過程
在狀態(tài)管理state中定義一個(gè)loginInfo對(duì)象用于存儲(chǔ)用戶的賬號(hào)和密碼
//在狀態(tài)管理文件中 import { defineStore } from 'pinia' import Cookies from "js.cookie" import {post} from '@/http' ? import router from '@/router'; import { ElMessage } from 'element-plus'; export const useUserStore = defineStore({ ? id: "userStore", ? persist: { ? ? paths:['user'] ? },//持久化 ? state: () => ({ ? ? loginInfo:{ ? ? ? username:'',? ? ? ? password:'' ? ? } ? }), ? getters: {}, ? actions: { ? ? setUser(user:UserInfo) { ? ? ? this.user = user; ? ? }, ? ? loginOut(){ ? ? ? const data ={ ? ? ? ? _gp:"admin", ? ? ? ? _mt:"logout" ? ? ? } ? ? ? post({},data).then((res:any)=>{ ? ? ? ? let {errmsg,errno} = res ? ? ? ? if(200==errno){ ? ? ? ? ? localStorage.removeItem("userStore") ? ? ? ? ? Cookies.remove("token") ? ? ? ? ? router.replace('/login') ? ? ? ? ? ElMessage.success(errmsg); ? ? ? ? }else{ ? ? ? ? ? ElMessage.error(errmsg); ? ? ? ? } ? ? ? }).catch(res=>{ ? ? ? console.log(res,"退出登入失敗"); ? ? ? }) ? ? } ? } })
登入頁面中,在登入請(qǐng)求成功后將用戶的賬號(hào)和密碼存儲(chǔ)在狀態(tài)管理
//在登入頁面文件中 const data = { ...ruleForm, _gp: "admin", _mt: "login" }//轉(zhuǎn)換成字符串 post({}, data).then(res => { ? ? let { data: token, errmsg, errno } = res as any;//獲取登錄狀態(tài) ? ? if (200 == errno) {//登錄成功的判斷 ? ? ? ? ElMessage.success("登錄成功!")//消息提示登錄成功 ? ? ? ? let now = new Date();//獲取當(dāng)前時(shí)間 ? ? ? ? now.setTime(now.getTime() + 1000 * 60 * 30);//轉(zhuǎn)成時(shí)間類型 ? ? ? ? Cookies.set("token", res.data, { expires: now })//獲取token存到cookie ? ? ? ? Object.assign(store.loginInfo, ruleForm)//將賬號(hào)密碼存儲(chǔ)到狀態(tài)管理 ? ? ? ? return Promise.resolve(token) ? ? } else { ? ? ? ? ElMessage.error(errmsg);//登入失敗 ? ? ? ? return Promise.reject(errmsg) ? ? } })
3.在http中,先定義一個(gè)數(shù)組變量,該數(shù)組存放需要無痛刷新的操作如:刪除、添加、編輯
4.在響應(yīng)攔截器中,判斷10006是否等于errno,如果相等說明令牌過期了,否則沒過期
5.令牌過期,獲取接口請(qǐng)求數(shù)據(jù)在定義的數(shù)組中查找判斷請(qǐng)求類型是否需要無痛刷新
6.index===-1則表示在數(shù)組中沒有找到也就不需要無痛刷新,直接跳到登入頁面進(jìn)行登入
7.index!==-1則表示需要無痛刷新,將狀態(tài)管理中存儲(chǔ)的用戶賬號(hào)和密碼解構(gòu)出來,進(jìn)行登入接口請(qǐng)求從而達(dá)到重新獲取令牌,進(jìn)而達(dá)到不需要進(jìn)入登入頁面就可以進(jìn)行登入請(qǐng)求也就達(dá)到無痛刷新的效果
//在封裝的http文件中 import axios, { type AxiosResponse } from 'axios'; import qs from 'qs' import Cookies from "js.cookie" import router from '@/router'; import { ElMessage } from 'element-plus'; import { useUserStore } from '@/stores/admin'; ? declare interface TypeResponse extends AxiosResponse { ? ? url(url: any): unknown; ? ? [x: string]: any; ? ? /** ? ? ?* 錯(cuò)誤號(hào),200表示成功,10006令牌過期 ? ? ?*/ ? ? errno: number, ? ? /** ? ? ?* 失敗返回的消息 ? ? ?*/ ? ? error: string, ? ? /** ? ? ?* 成功后返回的消息 ? ? */ ? ? errmsg: string ? } let baseURL = '' ? if (process.env.NODE_ENV === "development") { ? ? baseURL = '/m.api' } else { ? ? baseURL = "http://zxwyit.cn:8080/m.api"http://上線后的路徑 } ? const instance = axios.create({//創(chuàng)建實(shí)例 ? ? baseURL, ? ? headers: { "content-type": "application/x-www-form-urlencoded" } }) ? // 請(qǐng)求攔截器 instance.interceptors.request.use(function (config) { ? ? if (config.headers) { ? ? ? ? config.headers['AdminToken'] = Cookies.get("token") + '' ? ? } ? ? return config }, function (error) { ? ? console.error('請(qǐng)求錯(cuò)誤', error) ? ? return Promise.reject(error) } ) // 無痛刷新的原理:當(dāng)token過期后,在響應(yīng)攔截器通過判斷重新進(jìn)行登入請(qǐng)求 // 實(shí)現(xiàn)過程: // 1.在狀態(tài)管理state中定義一個(gè)loginInfo對(duì)象用于存儲(chǔ)用戶的賬號(hào)和密碼 // 2.登入頁面中,在登入請(qǐng)求成功后將用戶的賬號(hào)和密碼存儲(chǔ)在狀態(tài)管理 // 3.在http中,先定義一個(gè)數(shù)組變量,該數(shù)組存放需要無痛刷新的操作如:刪除、添加、編輯 // 4.在響應(yīng)攔截器中,判斷10006是否等于errno,如果相等說明令牌過期了,否則沒過期 // 5.令牌過期,獲取接口請(qǐng)求數(shù)據(jù)在定義的數(shù)組中查找判斷請(qǐng)求類型是否需要無痛刷新 // 6.index===-1則表示在數(shù)組中沒有找到也就不需要無痛刷新,直接跳到登入頁面進(jìn)行登入 // 7.index!==-1則表示需要無痛刷新,將狀態(tài)管理中存儲(chǔ)的用戶賬號(hào)和密碼解構(gòu)出來, // 進(jìn)行登入接口請(qǐng)求從而達(dá)到重新獲取令牌,進(jìn)而達(dá)到不需要進(jìn)入登入頁面就可以進(jìn)行登入請(qǐng)求也就達(dá)到無痛刷新的效果 ? // 需要無痛刷新的操作頁面 const METHOD_TYPE = ["_mt=edit", "_mt=create", "_mt=delete"] // 響應(yīng)攔截器 instance.interceptors.response.use(async function (response) { ? ? let data = response.data//強(qiáng)解 ? ? let { errno, errmsg } = data//結(jié)構(gòu)賦值 ? ? let path = router.currentRoute.value.fullPath//獲取路徑 ? ? console.log(errno,'errno'); ? ?? ? ? if (10006 == errno) { ? ? ? ? // 獲取接口請(qǐng)求數(shù)據(jù) ? ? ? ? const configData = response.config.data || '' ? ? ? ? // 判斷請(qǐng)求類型是否需要無痛刷新,index !== -1則需要無痛刷新 ? ? ? ? let index = METHOD_TYPE.findIndex(item => configData.includes(item)) ? ? ? ? if (-1 === index) {//需要重新登入獲取令牌 ? ? ? ? ? ? router.replace({ path: "/login", query: { back: path } })//登入后需要跳回的地址 ? ? ? ? ? ? return ? ? ? ? } else {//需要無痛刷新令牌 ? ? ? ? ? ? const store = useUserStore(); ? ? ? ? ? ? const { username, password } = store.loginInfo//在狀態(tài)管理里面定義一個(gè)loginInfo ? ? ? ? ? ? // 1.重新獲取令牌 ? ? ? ? ? ? let loginData = { _gp: 'admin', _mt: 'login', username, password }; ? ? ? ? ? ? const { errno, errmsg, data } = await post(loginData)//這里是通過async 將異步序列化改為同步 ? ? ? ? ? ? if (200 == errno) { ? ? ? ? ? ? ? ? ? Cookies.set('token', data)//保存令牌 ? ? ? ? ? ? } else { ? ? ? ? console.log(55); ? ? ? ? ? ? ? ? ? router.replace({ path: "/login", query: { back: path } })//登入后需要跳回的地址 ? ? ? ? ? ? ? ? return Promise.reject({ errno, errmsg,data}) ? ? ? ? ? ? } ? ? ? ? ? ? return instance.request(response.config) ? ? ? ? } ? ? } ? ? return data }, function (error) { ? ? console.error('響應(yīng)錯(cuò)誤', error) ? ? return Promise.reject(error) } ) function get(params?: object): Promise<TypeResponse> { ? ? return instance.get("", { params }) } function post(data: object, params?: object): Promise<TypeResponse> { ? ? return instance.post("", qs.stringify(data), { params }) } ? /** ?* 富文本框圖片上傳請(qǐng)求 ?*/ export function upload(data: object): Promise<TypeResponse> { ? ? return instance.post("http://192.168.1.188:8080/upload/admin", data); } ? export { get, post }?
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
vue項(xiàng)目中vue-i18n和element-ui國(guó)際化開發(fā)實(shí)現(xiàn)過程
這篇文章主要介紹了vue項(xiàng)目中vue-i18n和element-ui國(guó)際化開發(fā)實(shí)現(xiàn)過程,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2018-04-04elementUI中el-upload文件上傳的實(shí)現(xiàn)方法
ElementUI的組件支持多種事件鉤子,如http-request、before-upload和on-change,以實(shí)現(xiàn)自定義文件上傳處理,這篇文章主要介紹了elementUI中el-upload文件上傳的實(shí)現(xiàn)方法,需要的朋友可以參考下2024-11-11vue如何隨心所欲調(diào)整el-dialog中body的樣式
這篇文章主要介紹了vue如何隨心所欲調(diào)整el-dialog中body的樣式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05vue+vuex+axios實(shí)現(xiàn)登錄、注冊(cè)頁權(quán)限攔截
下面小編就為大家分享一篇vue+vuex+axios實(shí)現(xiàn)登錄、注冊(cè)頁權(quán)限攔截,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-03-03Vue 實(shí)現(xiàn)一個(gè)命令式彈窗組件功能
這篇文章主要介紹了vue實(shí)現(xiàn)命令式彈窗組件功能,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-09-09前端vue-cli項(xiàng)目中使用img圖片和background背景圖的幾種方法
這篇文章主要介紹了前端vue-cli項(xiàng)目中使用img圖片和background背景圖的幾種方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11element-ui和vue表單(對(duì)話框)驗(yàn)證提示語(殘留)清除操作
這篇文章主要介紹了element-ui和vue表單(對(duì)話框)驗(yàn)證提示語(殘留)清除操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-09-09