网址:https://element-plus.org/zh-CN/guide/installation.html
# NPM
$ npm install element-plus --save
如果你对打包后的文件大小不是很在乎,那么使用完整导入会更方便。
// main.ts
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'
const app = createApp(App)
app.use(ElementPlus)
app.mount('#app')
在引入 ElementPlus 时,可以传入一个包含 size
和 zIndex
属性的全局配置对象。 size
用于设置表单组件的默认尺寸,zIndex
用于设置弹出组件的层级,zIndex
的默认值为 2000
。
完整引入:
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import App from './App.vue'
const app = createApp(App)
app.use(ElementPlus, { size: 'small', zIndex: 3000 })
# NPM
$ npm install @element-plus/icons-vue
您需要从 @element-plus/icons-vue
中导入所有图标并进行全局注册。
// main.ts
// 如果您正在使用CDN引入,请删除下面一行。
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
const app = createApp(App)
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
要在输入框中添加图标,你可以简单地使用 prefix-icon
和 suffix-icon
属性。
<template>
<el-input
v-model="input2"
class="w-50 m-2"
placeholder="Type something"
:prefix-icon="Search"
/>
</template>
<script setup>
import { Calendar, Search } from '@element-plus/icons-vue'
</script>
网址:https://www.axios-http.cn/docs/intro
使用 npm:
$ npm install axios
<script setup>
//局部引入
import axios from "axios";
const user = reactive({
username:'',
password:''
});
function login(){
axios.post('http://localhost:9999/rbac/user/login', user)
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
创建axiosApi.js
import axios from "axios"
const instance = axios.create({
baseURL: 'http://localhost:9999',//请求根路径
timeout: 10000 //超时时间 10秒
});
// 添加请求拦截器
instance.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
instance.interceptors.response.use(function (response) {
// 2xx 范围内的状态码都会触发该函数。
// 对响应数据做点什么
return response;
}, function (error) {
// 超出 2xx 范围的状态码都会触发该函数。
// 对响应错误做点什么
return Promise.reject(error);
});
//暴露
export default instance;
使用(登录案例)
<template>
<div class="login">
<el-form :model="user" class="login-form">
<h1 class="title">用户登录</h1>
<el-form-item label="">
<el-input
v-model="user.username"
placeholder="请输入账号"
:prefix-icon="User"
>
</el-input>
</el-form-item>
<el-form-item label="">
<el-input
v-model="user.password"
placeholder="请输入密码"
:prefix-icon="Lock"
show-password
>
</el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="login">登录</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script setup>
import { reactive } from "vue"
import instance from "@/api/axiosApi"
import { User, Lock } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import router from '@/router'
const user = reactive({
username:'',
password:''
});
function login(){
// instance.request({method: 'post',url:'/rbac/user/login',data:user})
instance.post('/rbac/user/login', user)
.then(res =>{
if(res.data.code === 200){
//跳转home
router.push("/");
}else{
ElMessage(res.data.msg);
}
})
.catch(function (error) {
ElMessage(error);
});
}
</script>
<style scoped>
.login {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
}
.title {
margin: 0px auto 30px auto;
text-align: center;
color: #707070;
}
.login-form {
border-radius: 6px;
background: #ffffff;
width: 350px;
padding: 25px 25px 5px 25px;
}
button{
width: 100%;
}
</style>
官网:https://pinia.vuejs.org/zh/introduction.html
# 使用 npm
npm install pinia
创建一个 pinia 实例 (根 store) 并将其传递给应用:
js
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
const pinia = createPinia()
const app = createApp(App)
app.use(pinia)
app.mount('#app')
创建store文件夹,创建storeApi.js
import { defineStore } from 'pinia'
export const tokenStore = defineStore('token', {
//一个返回初始状态的函数
state: () => ({ token: null }),
//相当于组件中的 method
actions: {
updateToken(token) {
this.token = token;
},
},
})
登录保存token
<template>
<div class="login">
<el-form :model="user" class="login-form">
<h1 class="title">用户登录</h1>
<el-form-item label="">
<el-input
v-model="user.username"
placeholder="请输入账号"
:prefix-icon="User"
>
</el-input>
</el-form-item>
<el-form-item label="">
<el-input
v-model="user.password"
placeholder="请输入密码"
:prefix-icon="Lock"
show-password
>
</el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="login">登录</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script setup>
import { reactive } from "vue"
import instance from "@/api/axiosApi"
import { User, Lock } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import router from '@/router'
import { tokenStore } from '@/store/storeApi'
const user = reactive({
username:'',
password:''
});
function login(){
// instance.request({method: 'post',url:'/rbac/user/login',data:user})
instance.post('/rbac/user/login', user)
.then(res =>{
if(res.data.code === 200){
//保存token
tokenStore().updateToken(res.data.res);
//跳转home
router.push("/");
}else{
ElMessage(res.data.msg);
}
})
.catch(function (error) {
ElMessage(error);
});
}
</script>
<style scoped>
.login {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
}
.title {
margin: 0px auto 30px auto;
text-align: center;
color: #707070;
}
.login-form {
border-radius: 6px;
background: #ffffff;
width: 350px;
padding: 25px 25px 5px 25px;
}
button{
width: 100%;
}
</style>
拦截器添加token到header
import axios from "axios"
import { tokenStore } from '@/store/storeApi'
const instance = axios.create({
baseURL: 'http://localhost:9999',//请求根路径
timeout: 10000 //超时时间 10秒
});
// 添加请求拦截器
instance.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
console.log('instance.interceptors.request');
console.log(tokenStore().token);
//token放入header
config.headers['Authorization-Token'] = tokenStore().token;
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
instance.interceptors.response.use(function (response) {
// 2xx 范围内的状态码都会触发该函数。
// 对响应数据做点什么
return response;
}, function (error) {
// 超出 2xx 范围的状态码都会触发该函数。
// 对响应错误做点什么
return Promise.reject(error);
});
//暴露
export default instance;
App.vue
<script setup>
import { RouterLink, RouterView } from 'vue-router'
// import HelloWorld from './components/HelloWorld.vue'
import { tokenStore } from '@/store/storeApi'
let store = tokenStore();
if (sessionStorage.getItem("store")) {
store.updateToken(sessionStorage.getItem("store"))
}
//在页面刷新时将vuex里的信息保存到sessionStorage里
window.addEventListener("beforeunload",()=>{
console.log('刷新页面')
sessionStorage.setItem("store",store.token)
})
</script>
登录token有值,报403
第一种方式:请求拦截器将不需要验证的url的token设为null
import axios from 'axios'
import { tokenStore } from '@/store/storeApi'
import router from '@/router'
const instance = axios.create({
baseURL: 'http://localhost:9999',//请求根路径
timeout: 10000//超时时间
});
// 添加请求拦截器
instance.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
//判断是否需要token
if(config.url =='/rbac/user/login')
config.headers['Authorization-Token'] = null;
//将token添加到header
else
config.headers['Authorization-Token'] = tokenStore().token;
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
instance.interceptors.response.use(function (response) {
// 2xx 范围内的状态码都会触发该函数。
// 对响应数据做点什么
return response;
}, function (error) {
// 超出 2xx 范围的状态码都会触发该函数。
// 对响应错误做点什么
console.log('error');
console.log(error.response.status);
//没有权限
if(error.response.status == 403){
//跳转到登录页
router.push('/login');
}
return Promise.reject(error);
});
//暴露
export default instance;
第二种方式:在router文件夹下的index.js中添加路由守卫
router.beforeEach((to, from, next) => {
const isAuthenticated = tokenStore().token == null ? false:true;
//访问登录页 token赋值null
if(to.name === 'Login'){
tokenStore().token = null;
}
//访问非登录页且token是null
if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
else next()
})