项目结构
vue3-ts-cms
├─ .browserslistrc
├─ .editorconfig
├─ .env.development
├─ .env.production
├─ .env.test
├─ .eslintrc.js
├─ .gitignore
├─ .prettierignore
├─ .prettierrc
├─ babel.config.js
├─ package-lock.json
├─ package.json
├─ public
│ ├─ favicon.ico
│ └─ index.html
├─ README.md
├─ src
│ ├─ App.vue
│ ├─ assets
│ │ └─ css
│ │ ├─ base.less
│ │ ├─ index.less
│ ├─ components
│ ├─ global
│ │ ├─ index.ts
│ │ └─ register-element.ts
│ ├─ main.ts
│ ├─ router
│ │ └─ index.ts
│ ├─ service
│ │ ├─ index.ts
│ │ └─ request
│ │ ├─ config.ts
│ │ ├─ index.ts
│ │ └─ type.ts
│ ├─ shims-vue.d.ts
│ ├─ store
│ │ └─ index.ts
│ └─ views
│ ├─ login
│ │ └─ login.vue
│ └─ main
│ └─ main.vue
├─ tsconfig.json
└─ vue.config.js
axios集成
安装axios
npm install axios
封装axios,在根目录下创建 service 文件夹,并在 service 下创建 index.ts 文件和 request 文件夹。之后在 request 文件夹里面创建 index.ts 、 type.ts、config.ts文件
这里封装一个axios,主要用于给所有请求添加token处理、是否显示loading状态等
service/request/type.ts
import type { AxiosRequestConfig } from 'axios'
export interface RycRequestConfig extends AxiosRequestConfig {
showLoading?: boolean
addToken?: boolean
}
service/request/config.ts
let BASE_URL = ''
const TIME_OUT = 10000
// 开发环境
if (process.env.NODE_ENV === 'development') {
// BASE_URL = '/api'
BASE_URL = 'https://www.fastmock.site/mock/89efb181f2e22e0b4044eee348889b6e/kjhs'
}
// 生产环境
else if (process.env.NODE_ENV === 'production') {
BASE_URL = ''
}
// 测试环境
else if (process.env.NODE_ENV === 'test') {
BASE_URL = ''
}
export { BASE_URL, TIME_OUT }
service/request/index.ts
import axios from 'axios'
import type { AxiosInstance } from 'axios'
import LocalCache from '@/utils/cache'
import type { RycRequestConfig } from './type'
import { ElLoading } from 'element-plus/lib/components'
import type { ILoadingInstance } from 'element-plus/lib/components/loading/src/loading.type'
// 默认显示loading
const DEFAULT_LOADING = true
// 默认当前axios请求附带token
const DEFAULT_ADD_TOKEN = true
class RycRequest {
private instance: AxiosInstance
// axios请求时,页面是否显示loading状态
private showLoading: boolean
// 当前axios请求是否附带token
private addToken: boolean
// 保存当前loading状态
private loading?: ILoadingInstance
constructor(config: RycRequestConfig) {
// 创建一个axios实例,防止多个实例相互干扰
this.instance = axios.create(config)
// 保存基本信息
this.showLoading = config.showLoading ?? DEFAULT_LOADING
this.addToken = config.addToken ?? DEFAULT_ADD_TOKEN
// 所有axios实例的请求成功、请求失败的拦截器(如:请求发送时开启loading状态)
this.instance.interceptors.request.use(
(config) => {
if (this.addToken) {
// 给请求添加token
const token = LocalCache.getLocalCache('token')
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
}
if (this.showLoading) {
this.loading = ElLoading.service({
lock: true,
text: '正在请求数据......',
background: 'rgba(0, 0, 0, 0.5)'
})
}
return config
},
(error) => {
// 请求失败,关闭页面loading状态
this.loading?.close()
return error
}
)
// 所有axios实例的响应成功、响应失败的拦截器(如:请求完成时关闭loading状态)
this.instance.interceptors.response.use(
(res) => {
// 响应成功,关闭页面loading状态
this.loading?.close()
//TODO 请求成功,但是服务端检查逻辑错误,显示对应的错误提示
// if (data.returnCode === '-1001') {
// console.log('请求失败~, 错误信息')
// } else {
// return data
// }
return res.data
},
(error) => {
// 响应失败,关闭页面loading状态
this.loading?.close()
//TODO 请求失败,服务端运行异常,显示对应的错误页面
// if (err.response.status === 404) {
// console.log('404的错误~')
// }
return error
}
)
}
require<T>(config: RycRequestConfig): Promise<T> {
return new Promise((resolve, reject) => {
// 根据请求设置,页面是否显示loading状态
if (config.showLoading === !DEFAULT_LOADING) {
this.showLoading = !DEFAULT_LOADING
}
// 根据请求设置,axios是否附带token
if (config.addToken === !DEFAULT_ADD_TOKEN) {
this.addToken = !DEFAULT_ADD_TOKEN
}
this.instance
.request<any, T>(config)
.then((res) => {
// 重新初始化showLoading,防止影响下一次请求
this.showLoading = DEFAULT_LOADING
resolve(res)
})
.catch((error) => {
// 重新初始化showLoading,防止影响下一次请求
this.showLoading = DEFAULT_LOADING
reject(error)
})
})
}
get<T = any>(config: RycRequestConfig): Promise<T> {
return this.require<T>({ ...config, method: 'GET' })
}
post<T = any>(config: RycRequestConfig): Promise<T> {
return this.require<T>({ ...config, method: 'POST' })
}
delete<T = any>(config: RycRequestConfig): Promise<T> {
return this.require<T>({ ...config, method: 'DELETE' })
}
patch<T = any>(config: RycRequestConfig): Promise<T> {
return this.require<T>({ ...config, method: 'PATCH' })
}
}
export default RycRequest
由于要对全局的axios请求数据添加token,而token一般是缓存到本地。
所以先封装一个存取token到本地缓存的方法。
在根目录下创建 utils 文件夹,再在此文件夹下创建 cache.ts文件
utils/cache.ts
class LocalCache {
setLocalCache(key: string, value: any) {
window.localStorage.setItem(key, JSON.stringify(value))
}
getLocalCache(key: string) {
const value = window.localStorage.getItem(key)
if (value) {
return JSON.parse(value)
}
}
removeLocalCache(key: string) {
window.localStorage.removeItem(key)
}
clearLocalCache() {
window.localStorage.clear()
}
}
export default new LocalCache()
对全局的axios请求数据添加token处理
service/index.ts
import RycRequest from './request'
import { BASE_URL, TIME_OUT } from './request/config'
const rycRequest = new RycRequest({
baseURL: BASE_URL,
timeout: TIME_OUT
})
export default rycRequest
配置不同环境变量
在开发中,有时候我们需要根据不同的环境设置不同的环境变量,常见的有三种环境:
- 开发环境:development
- 生产环境:production
- 测试环境:test
区分环境变量的两个方式
- 方式一:使用
process.env.NODE_ENV
来区分环境
在上述集成axios的代码中就是用此方式。
- 方式二:编写不同的环境变量配置文件
在根目录下创建 .env.development、.env.production、.env.test文件。参考资料
.env.development
VUE_APP_BASE_URL = 127.0.0.1:8080/zrr/dev
.env.production
VUE_APP_BASE_URL = 127.0.0.1:8080/zrr/prod
.env.test
.
VUE_APP_BASE_URL = 127.0.0.1:8080/zrr/test
取值方式:process.env.VUE_APP_BASE_URL