一,vuex
1.安装
npm i vuex@next
2.在src文件夹下面创建store文件夹(如图所示)
- 我们在index.ts中开始写我们的vuex
// 创建状态管理
import { createStore } from "vuex";
// 根节点状态属性
interface IRootState {
// 这里可以做一下属性记录
}
// 动态引入其他子模块
let modulesFiles = import.meta.globEager('./modules/*.ts')
let fileListFun = (list:any) => {
return Object.keys(list).reduce((moduless:any, modulePath:any) => {
const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1').split('/')[ modulePath.replace(/^\.\/(.*)\.\w+$/, '$1').split('/').length - 1]
const value = list[modulePath]
moduless[moduleName] = value.default
return moduless
}, {})
}
const modules = fileListFun(modulesFiles)
const store = createStore<IRootState>({
state:{},
mutations:{},
actions:{},
modules:{
...modules
}
})
export default store
- 在main.ts中引入
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import store from './store/index'
const app = createApp(App)
app.use(store).use(ElementPlus).mount('#app')
3.我们以登录为例写一个模块(如图所示)创建login.ts
login.ts
import api from '../../api/login' //引入的登录接口api
import { Module } from 'vuex' //子模块必须添加
//根节点状态属性约束
interface IRootState {
}
//state属性约束
interface ILoginState {
userInfo:{},
token:string
}
const state:any = {}
const mutations:any = {}
const actions:any = {}
//动态使用调用
for (const key in api) {
if(api[key].mutationsName) {
state[api[key].stateName] = api[key].stateDefaultName || ''
mutations[api[key].mutationsName] = (state:any, data:any) => {
if(api[key].getStateName) {
let getStateNameList = api[key].getStateName.split('.')
let i = 0
let stateValue = data
while(i< getStateNameList.length) {
stateValue = stateValue[getStateNameList[i]]
i++
}
state[api[key].stateName] = stateValue
} else {
state[api[key].stateName] = data
}
}
}
actions[key] = async ({commit}:any, params = {}) => {
if(api[key].mutationsName) {
let res = await api[key].requestFun(params)
commit(api[key].mutationsName, res)
return res
} else {
let res = await api[key].requestFun(params)
return res
}
}
}
const loginModule:Module<ILoginState,IRootState> = {
namespaced:true,
state,
mutations,
actions
}
export default loginModule
二, axios封装请求接口
1.在src文件夹的utils文件夹中新建baseUrl.ts文件 baseUrl.ts:
export const getBaseUrl = () =>{
let baseURL = ''
if(import.meta.env.Env === 'development'){
baseURL = 'https://demo.fat.net' //测试请求地址
} else {
baseURL = 'https://demo.net' //线上请求地址
}
return baseURL
}
2.安装axios
npm i axios
1.在src文件夹的utils文件夹中新建request.ts文件开始封装请求
import Axios from "axios";
import { getBaseUrl } from "./baseUrl";
import { useRouter, useRoute } from 'vue-router';
import { errorCodeType } from "./error-code-type"; //请求错误类型
import { ElMessage, ElLoading } from 'element-plus'
const BASE_URL = getBaseUrl()
const TIME_OUT: any = ''
const router = useRouter(), route = useRoute()
const instance = Axios.create({
baseURL: BASE_URL,
timeout: TIME_OUT,
withCredentials: false,
headers: {
'Content-Type': 'application/json;charset=utf-8',
// token:localStorage.getItem('token')
}
})
export function sendPost(url: string, data = {}, methods = "post") {
return new Promise((resolve, reject) => {
instance({
url: url,
method: methods,
data
}).then((res: any) => {
if(res.code == 0) {
resolve(res.data)
} else if (res.code == 413) {
ElMessage.error(res.message)
localStorage.removeItem('token')
localStorage.removeItem('name')
localStorage.removeItem('avatar_url')
//localStorage.removeItem('breadCrumbList')
//localStorage.removeItem('institution')
router.replace('/login')
} else {
ElMessage.error(res.message)
reject(res.message)
}
}).catch(err => {
reject(err);
});
})
}
let loading: any
// 正在请求的数量
let requestCount: number = 0
// 显示loading
const showLoading = () => {
if (requestCount === 0 && !loading) {
loading = ElLoading.service({
text: '加载中,请稍后...',
background: 'rgba(0,0,0,.7)',
spinner: 'el-icon-loading'
})
}
requestCount++
}
// 隐藏loading
const hideLoading = () => {
requestCount--
if (requestCount == 0) {
loading.close()
}
}
interface configRule {
[key: string]: any
}
instance.interceptors.request.use((config: configRule) => {
showLoading()
//是否需要设置 token
config.headers['token'] = localStorage.getItem('token')
if (config.method === 'get' && config.params) {
let url = config.url + '?'
for (const propName of Object.keys(config.params)) {
const value = config.params[propName]
var part = encodeURIComponent(propName) + '='
if (value !== null && typeof (value) !== 'undefined') {
if (typeof value === 'object') {
for (const key of Object.keys(value)) {
let params = propName + '[' + key + ']'
var subPat = encodeURIComponent(value[key]) + '&'
}
} else {
url += part + encodeURIComponent(value) + '&'
}
}
}
url = url.slice(0, -1)
config.params = {}
config.url = url
}
return config
}), (error: any) => {
return Promise.reject(error)
}
instance.interceptors.response.use((res: any) => {
hideLoading()
const code = res.data['code'] || 200
const msg = errorCodeType(code) || res.data['msg']
if (code == 200) {
return Promise.resolve(res.data)
} else {
ElMessage.error(msg)
return Promise.reject(res.data)
}
// const res = response.data
}), (error: any) => {
hideLoading()
let { message } = error
if (message == 'Network Error') {
message = '后端接口连接异常'
} else if (message.includes('timeout')) {
message = '系统接口请求超时'
} else if (message.includes('Request failed with status code')) {
message = '系统接口' + message.substr(message.length - 3) + '异常'
}
ElMessage.error({
message: message,
duration: 5 * 1000
})
return Promise.reject(error)
}
error-code-type.ts
export const errorCodeType = function (code: number) {
let msg: string = ''
switch (code) {
case 400:
msg = '请求错误'
break
case 401:
msg = '未授权,请登录'
break
case 403:
msg= '拒绝访问'
break
case 404:
msg = `请求地址出错: `
break
case 408:
msg = '请求超时'
break
case 500:
msg = '服务器开个小差,请稍后再试'
break
case 501:
msg = '服务器开个小差,请稍后再试'
break
case 502:
msg = '服务器开个小差,请稍后再试'
break
case 503:
msg = '服务器开个小差,请稍后再试'
break
case 504:
msg = '服务器开个小差,请稍后再试'
break
case 505:
msg = 'HTTP版本不受支持'
break
default:
msg = '请求失败,请稍后再试'
}
return msg
}
基础封装已经完毕,我们就可以去封装请求了
3.接口封装:在src文件夹下面创建api文件夹,以login为例,我们在api文件夹下面创建一个login.ts
login.ts:
import { sendPost } from '../utils/request'
interface apiRule{ //简约版
[key:string]:any
}
interface apiRule{ //详细版
[key:string]:{
url:string,
mutationsName?:string,
stateName?:string
}
}
const api:apiRule = {
'login': {
url:'/login/login/index'
},
'demo': {//如果接口内容需要进行数组修改mutations,或者state时
url: '/demo/demo',
mutationsName: 'mutationsDemo',
stateName: 'stateDemo',
},
}
const requestFunObj:any = {}
for (const key in api) {
requestFunObj[key] = {
...api[key],
requestFun:(params:any, method='post') => {
return sendPost(api[key].url, params, method)
}
}
}
export default requestFunObj