vue3+ts+axios+pinia实现无感刷新方式

 更新时间:2023年04月19日 11:09:44   作者:南庐  
这篇文章主要介绍了vue3+ts+axios+pinia实现无感刷新方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

vue3+ts+axios+pinia实现无感刷新

1.先在项目中下载aiXos和pinia

npm i pinia --save
npm install axios --save

2.封装axios请求-----

下载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);//判断环境
if (process.env.NODE_ENV === 'development') {
    baseURL = '/m.api'//后台请求接口地址
} else {
    baseURL = 'http://xxxx.cn:8080';//这里是项目上线后的地址
   
}
declare interface TypeResponse extends AxiosResponse {
    /**
     * 错误号,200表示成功,10006令牌过期
     */
    errno: number,
    /**
     * 返回的信息
     */
    errmsg: string
}
 
//创建axios实例
 
const instance = axios.create({
    baseURL,  // 接口地址
    timeout: 3000,
    headers: {
        "Content-Type": 'application/x-www-form-urlencoded'
    }
 
});
 
 
//添加拦截器
instance.interceptors.request.use((config) => {
    // 在发送请求之前做些什么--给请求头添加令牌token
    (config as any).headers['AdminToken'] = Cookie.get('token')//从cookie中拿token值,
//这里是使用了js-cookie插件。
    // console.log(config, "请求拦截器")
    return config
}, reeor => {
    // 对请求错误做些什么
    return Promise.reject(reeor);
});
// 需要无痛刷新的操作页面
const METHOD_TYPE = ["_mt=edit", "_mt=create", "_mt=delete"]
// //响应拦截器
instance.interceptors.response.use(async (response: AxiosResponse) => {
    // 对响应数据做点什么
    let data = response.data;
    let { errno, errmsg } = data;
    console.log(response, "响应拦截器");
    let path = router.currentRoute.value.fullPath;//当前路由路径
    if (10006 === errno) {
        const configData = response.config.data || ''
        // 判断请求类型是否需要无痛刷新,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//在状态管理里面定义一个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);//错误信息
    }
    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 });
};
 
 
//暴露实列
export {
    post, get,
}

3.qs.stringify(data)是将请求的数据转成表单格式,如果不需要直接去掉就可以了;

4.重新登录后跳转路由需要设置,不需要可以去掉

5。状态管理--数据

下载持久化工具

npm install pinia-plugin-persistedstate --s

在main.js中配置持久化

//引入数据持久化插件
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;//状态存储持久化
})

6.登录页面--存储表单数据,也就是用户名和密码

npm i lodash --s
import Cookies from 'js-cookie';//引入cookie
import * as _ from 'lodash';//防抖节流插件
import {post} from '@/util';
import {useUserInfoStore} from '@/stores/modules/UserInfo' ;//用户信息
import { useRouter,useRoute } from 'vue-router' ;//引入路由
//这里是表单输入的数据
const ruleForm = reactive({
    password: '123456',
    username: 'admin'
});
//请求接口数据
let data = {
    _gp: "admin",
    _mt: 'login',
    ...ruleForm
};
 
let LoginInfo = useUserInfoStore().LoginInfo;//状态管理定义的数据
async function init() {
    await post(data).then((res:any) => {
        let { data: token, errno, errmsg } = res
        if (200 === errno) {
            let time = new Date() //设置过期时间
            time.setTime(time.getTime() + 1000 * 60 * 30)
            Cookies.set('token', token, { expires: time });
            Object.assign(LoginInfo,ruleForm)
            if (route.query.back) { //如果存在参数
             let paths = route.query.back+''//拼接字符串
             console.log(paths);
             if (paths=='/') {
//因为我的home是'/',所有需要判断
                router.replace('/Surface')//跳转至主页
                return
             }else{
                router.replace(paths)//则跳转至进入登录页前的路由
             }
             
           } else {
            router.replace('/Surface')//否则跳转至首页
           }
            
        } else {
            ElMessage.error(errmsg)
        }
    }).catch((err:any) => {
        ElMessage.error('登录异常!')
    })
    let info = {//用户信息请求信息接口数据
        _gp: "admin",
        _mt: 'info',
    }
//下面这个函数是请求用户信息的,不需要可以不写
    await post(info).then((res:any) => {
        let {data} = res
        console.log(data);
        infos(data)
 
    }).catch((err:any)=>{
        ElMessage.error('登录异常!')
    })
}
//防抖节流
const fangdou = _.debounce(init, 1500, {
    leading: true,  // 延长开始后调用
    trailing: false  // 延长结束前调用
})
//移除组件时,取消防抖
onUnmounted(() => {
    fangdou.cancel()
})

7.main.js设置路由守卫

import Cookie from 'js-cookie'
import router from './router'//引入路由
 
//路由守卫
router.beforeEach(async (to, from ) => {
    let tokent:string|undefined = Cookie.get('token')
    if (!tokent && to.path == '/login') {
        return  true
    }
    // 没有登录,强制跳转登录页
    if (!tokent && to.path !== '/login') {
        router.replace({path:'/login',query:{back:to.path}});
    }
    // 防止重复登录
    if (tokent && to.path === '/login') {
        return {
            path: from.path ? from.path : '/Surface'
        }
    }
    return true
})

大概就是这么多了

vue3无痛刷新(无感刷新)

无痛刷新的原理:当token过期后,在响应拦截器通过判断重新进行登入请求

实现过程

在状态管理state中定义一个loginInfo对象用于存储用户的账号和密码

//在状态管理文件中
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,"退出登入失败");
      })
    }
  }
})

登入页面中,在登入请求成功后将用户的账号和密码存储在状态管理

//在登入页面文件中
const data = { ...ruleForm, _gp: "admin", _mt: "login" }//转换成字符串
post({}, data).then(res => {
    let { data: token, errmsg, errno } = res as any;//获取登录状态
    if (200 == errno) {//登录成功的判断
        ElMessage.success("登录成功!")//消息提示登录成功
        let now = new Date();//获取当前时间
        now.setTime(now.getTime() + 1000 * 60 * 30);//转成时间类型
        Cookies.set("token", res.data, { expires: now })//获取token存到cookie
        Object.assign(store.loginInfo, ruleForm)//将账号密码存储到状态管理
        return Promise.resolve(token)
    } else {
        ElMessage.error(errmsg);//登入失败
        return Promise.reject(errmsg)
    }
})

3.在http中,先定义一个数组变量,该数组存放需要无痛刷新的操作如:删除、添加、编辑

4.在响应拦截器中,判断10006是否等于errno,如果相等说明令牌过期了,否则没过期

5.令牌过期,获取接口请求数据在定义的数组中查找判断请求类型是否需要无痛刷新

6.index===-1则表示在数组中没有找到也就不需要无痛刷新,直接跳到登入页面进行登入

7.index!==-1则表示需要无痛刷新,将状态管理中存储的用户账号和密码解构出来,进行登入接口请求从而达到重新获取令牌,进而达到不需要进入登入页面就可以进行登入请求也就达到无痛刷新的效果

//在封装的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;
    /**
     * 错误号,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"//上线后的路径
}
 
const instance = axios.create({//创建实例
    baseURL,
    headers: { "content-type": "application/x-www-form-urlencoded" }
})
 
// 请求拦截器
instance.interceptors.request.use(function (config) {
    if (config.headers) {
        config.headers['AdminToken'] = Cookies.get("token") + ''
    }
    return config
}, function (error) {
    console.error('请求错误', error)
    return Promise.reject(error)
}
)
// 无痛刷新的原理:当token过期后,在响应拦截器通过判断重新进行登入请求
// 实现过程:
// 1.在状态管理state中定义一个loginInfo对象用于存储用户的账号和密码
// 2.登入页面中,在登入请求成功后将用户的账号和密码存储在状态管理
// 3.在http中,先定义一个数组变量,该数组存放需要无痛刷新的操作如:删除、添加、编辑
// 4.在响应拦截器中,判断10006是否等于errno,如果相等说明令牌过期了,否则没过期
// 5.令牌过期,获取接口请求数据在定义的数组中查找判断请求类型是否需要无痛刷新
// 6.index===-1则表示在数组中没有找到也就不需要无痛刷新,直接跳到登入页面进行登入
// 7.index!==-1则表示需要无痛刷新,将状态管理中存储的用户账号和密码解构出来,
// 进行登入接口请求从而达到重新获取令牌,进而达到不需要进入登入页面就可以进行登入请求也就达到无痛刷新的效果
 
// 需要无痛刷新的操作页面
const METHOD_TYPE = ["_mt=edit", "_mt=create", "_mt=delete"]
// 响应拦截器
instance.interceptors.response.use(async function (response) {
    let data = response.data//强解
    let { errno, errmsg } = data//结构赋值
    let path = router.currentRoute.value.fullPath//获取路径
    console.log(errno,'errno');
    
    if (10006 == errno) {
        // 获取接口请求数据
        const configData = response.config.data || ''
        // 判断请求类型是否需要无痛刷新,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//在状态管理里面定义一个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('响应错误', 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 })
}
 
/**
 * 富文本框图片上传请求
 */
export function upload(data: object): Promise<TypeResponse> {
    return instance.post("http://192.168.1.188:8080/upload/admin", data);
}
 
export { get, post } 

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • vue-cli2.0转3.0之项目搭建的详细步骤

    vue-cli2.0转3.0之项目搭建的详细步骤

    这篇文章主要介绍了vue-cli2.0转3.0之项目搭建的详细步骤,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-12-12
  • 一文带你了解Vue中的axios和proxy代理

    一文带你了解Vue中的axios和proxy代理

    这篇文章主要为大家详细介绍了Vue中的axios和proxy代理的相关知识,文中的示例代码讲解详细,具有一定的借鉴价值,需要的可以参考一下
    2023-03-03
  • vue跳转方式(打开新页面)及传参操作示例

    vue跳转方式(打开新页面)及传参操作示例

    这篇文章主要介绍了vue跳转方式(打开新页面)及传参操作,结合实例形式分析了vue.js跳转实现方式与参数接受相关操作技巧,需要的朋友可以参考下
    2020-01-01
  • vue2.* element tabs tab-pane 动态加载组件操作

    vue2.* element tabs tab-pane 动态加载组件操作

    这篇文章主要介绍了vue2.* element tabs tab-pane 动态加载组件操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-07-07
  • Vue3 Hooks 模块化抽离示例详解

    Vue3 Hooks 模块化抽离示例详解

    这篇文章主要为大家介绍了Vue3 Hooks 模块化抽离示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-09-09
  • vue2前端调用WebSocket有消息进行通知代码示例

    vue2前端调用WebSocket有消息进行通知代码示例

    在Vue项目中实现全局的消息链接监听主要涉及到了WebSocket技术,这是一种双向通信协议,允许客户端与服务器之间实时、高效地交换数据,这篇文章主要给大家介绍了关于vue2前端调用WebSocket有消息进行通知的相关资料,需要的朋友可以参考下
    2024-07-07
  • vue-cli脚手架打包静态资源请求出错的原因与解决

    vue-cli脚手架打包静态资源请求出错的原因与解决

    这篇文章主要给大家介绍了关于vue-cli脚手架打包静态资源请求出错的原因与解决方法,文中通过示例代码介绍的非常详细,对大家学习或者使用vue-cli具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-06-06
  • 详解vue如何获取当前系统时间

    详解vue如何获取当前系统时间

    这篇文章主要详细介绍了vue如何获取当前系统时间,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2024-01-01
  • Vue滑块解锁组件使用方法详解

    Vue滑块解锁组件使用方法详解

    这篇文章主要为大家详细介绍了Vue滑块解锁组件的使用方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • Vue新一代状态管理工具Pinia的具体使用

    Vue新一代状态管理工具Pinia的具体使用

    本文主要介绍了Vue新一代状态管理工具Pinia的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-07-07

最新评论