为了跨组件传递JWT令牌,我们就会利用Pinia状态管理库,它允许跨组件或页面共享状态。
使用Pinia步骤:
安装pinia:cnpm install pinia
在vue应用实例中使用pinia
在src/stores/token.js中定义store
在组件中使用store
1.在main.js文件导入pinia:
这里因为Pinia是默认内存存储,刷新浏览器会丢失数据,我们使用pinia内的Persist插件就可以将Pinia中的数据持久化存储。
为了使用persist,我们需要安装persist:cnpm install pinia-persistedstate-plugin,然后再pinia中使用persist,并且需要再main.js导入一下。
import './assets/main.scss'
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'
import router from '@/router'
import { createPinia } from 'pinia'
import { createPersistedState } from 'pinia-persistedstate-plugin'
const app = createApp(App);
//创建createPinia()函数实例
const pinia = createPinia();
const persist = createPersistedState();
pinia.use(persist)
app.use(pinia)
app.use(router)
app.use(ElementPlus);
app.mount('#app')
2.定义store状态:
其实无外乎就是使用defineStore()方法,在方法内部分为两个参数来写 :
第一个参数:名字,确保唯一性。
第二个参数:函数,其内部可以定义状态的所有内容,其内部先创建一个响应式数据,然后设置获取数据以及删除数据的方法,最后返回数据以及方法。加上Persist插件就可以将Pinia中的数据持久化存储。
//定义store
import { defineStore } from "pinia";
import {ref} from 'vue'
/*
第一个参数:名字,确保唯一性
第二个参数:函数,其内部可以定义状态的所有内容
返回值:函数
*/
export const useTokenStore = defineStore('token',()=>{
//定义状态内容
//1.定义响应式变量
const token = ref('');
//2.定义函数来修改token值
const setToken = (newToken)=>{
token.value = newToken;
}
//3.定义函数来移除token值
const removeToken = ()=>{
token.value = '';
}
return {
token,setToken,removeToken
}
},{
persist: true //因为Pinia是默认内存存储,刷新浏览器会丢失数据,使用Persist插件就可以将Pinia中的数据持久化存储
}
);
这样我们就可以调用定义的useTokenStore来使用pinia了。
eg:文章分类列表渲染:
我们的目的是想要通过pinia来跨组件使用token请求头内的JWT令牌,将其封装给请求头。
我们首先再Login.vue文件中把得到的token存储到pinia中:
//导入store状态
import { useTokenStore } from '@/stores/token.js';
//导入路由器
import { useRouter } from 'vue-router';
const tokenstore = useTokenStore();
const router = useRouter();
//表单数据校验
const login = async()=>{
let result = await userLoginService(registerData.value);
// alert(result.msg ? result.msg : '登录成功');
ElMessage.success(result.msg ? result.msg : '登录成功');
//将得到的token存储到pinia中
tokenstore.setToken(result.data);
//通过路由跳转首页
router.push('/');
}
然后再article.js中定义请求函数:
import request from '@/utils/request.js'
import { useTokenStore } from '@/stores/token.js';
export const ArticleCategoryListService = ()=>{
const tokenStore = useTokenStore();
//在pinia中定义的响应式数据不需要加.value才能使用数据
return request.get('/category',{headers:{'Authorization':tokenStore.token}});
}
但是这样我们需要将剩下的请求函数都要传递JWT令牌,代码会很繁琐,这个时候我们就可以添加请求拦截器来使用回调函数来发送。
添加请求拦截器:
在request.js文件中添加请求拦截器:
import { useTokenStore } from '@/stores/token.js';
//添加请求拦截器
instance.interceptors.request.use(
(config)=>{
//请求前的回调
const tokenStore = useTokenStore();
if(tokenStore.token){
//通过config调用headers获取请求头,在调用Authorization将JWT令牌存放到内部以此来添加统一的请求头
config.headers.Authorization = tokenStore.token;
}
return config;
},
(err)=>{
//请求错误的回调
Promise.reject(err);//异步的状态转化成失败的状态
}
)
export default instance;
修改article.js文件的请求函数:
import request from '@/utils/request.js'
export const ArticleCategoryListService = ()=>{
return request.get('/category');
}