vue3+vueRouter + vueX 项目新建
vue create demo
cd demo(cd 到项目)
npm run serve(此时已经运行起来)
安装插件
npm install element-plus
npm intsall @element-plus/icons-vue
npm install axios(axios)
npm install qs(序列化)
引入插件
引入element 和icons
// main.ts里
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
// 引入elementPlus
import ElementPlus from 'element-plus'
import zhCn from 'element-plus/es/locale/lang/zh-cn'
import 'element-plus/dist/index.css'
// 引入字体文件
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
(async () => {
const app = createApp(App)
// 使用字体文件
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
app.use(store).use(router).use(ElementPlus, { locale: zhCn }).mount("#app")
})
vue.config.js(vue3.0需要自己建立vue.config.js,在根目录下,与src同级)
const path = require('path')
const webpack = require('webpack')
const IS_PROD = ['production', 'test'].includes(process.env.NODE_ENV)
module.exports = {
// 部署应用包时的基本 URL,用法和 webpack 本身的 output.publicPath 一致
publicPath: './',
// 输出文件目录
outputDir: 'dist',
// eslint-loader 是否在保存的时候检查
lintOnSave: true,
// 是否使用包含运行时编译器的 Vue 构建版本
runtimeCompiler: false,
// 生产环境是否生成 sourceMap 文件
productionSourceMap: false,
// 生成的 HTML 中的 <link rel="stylesheet"> 和 <script> 标签上启用 Subresource Integrity (SRI)
integrity: false,
// webpack相关配置
chainWebpack: (config) => {
config.plugin('html')
.tap(args => {
args[0].title = '项目名称';
return args;
})
},
configureWebpack: (config) => {
if (process.env.NODE_ENV === 'production') {
//生产环境
config.mode = 'production'
} else {
//开发环境
config.mode = 'development'
}
},
// css相关配置
css: {
// 是否分离css(插件ExtractTextPlugin)
extract: IS_PROD,
// 是否开启 CSS source maps
sourceMap: false,
// css预设器配置项
loaderOptions: {
sass: {
// prependData: `@import "~@/assets/scss/variable.scss";`,
// 公共css
}
},
// 是否启用 CSS modules for all css / pre-processor files.
modules: false
},
// 是否使用 thread-loader
parallel: require('os').cpus().length > 1,
// PWA 插件相关配置
pwa: {},
// webpack-dev-server 相关配置
devServer: {
open: false,
host: 'XXX.XXX.X.XXX', // 服务器地址
port: 8090, // 端口,可以自己改
https: false,
hotOnly: false,
before: (app) => { }
},
// 第三方插件配置
pluginOptions: {
}
}
接口地址(public下建立serverconfig.json文件)
token 存储
将token存储到cookie里
新建文件untils->auth.ts
const TokenKey = 'PROJECTKEY'
export function getToken(): (string | null) {
let arr: any
let reg = new RegExp('(^| )' + TokenKey + '=([^;]*)(;|$)')
if (arr = document.cookie.match(reg)) {
console.log(arr)
return unescape(arr[2])
} else {
return null
}
}
export function setToken(token: string) {
let Days = 30
let exp = new Date()
exp.setTime(exp.getTime() + Days * 24 * 60 * 60 * 1000)
document.cookie = TokenKey + '=' + escape(token) + ';expires=' + exp.toUTCString() + '; path=/'
}
export function removeToken() {
let exp = new Date()
exp.setTime(exp.getTime() - 1)
let cval = getCookieLocal(TokenKey)
if (cval != null) {
document.cookie = TokenKey + '=' + cval + ';expires=' + exp.toUTCString() + '; path=/'
}
}
let getCookieLocal = function (name: string) {
let arr, reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)')
if (arr = document.cookie.match(reg))
return unescape(arr[2])
else
return null;
}
接口地址
public下新建 serverconfig.json
{
"ApiUrl": "xxxxxxxxxxxx", // 接口地址
"Title": "Project" //项目名称
}
store 封装
①. store文件下新建 modules 文件夹(文件夹下新建 common.ts和user.ts) 和getters.ts
common.ts (来存储接口路径)
import axios from "axios";
import { Commit } from "vuex";
const state = {
axiosBaseUrl: ''
}
const mutations = {
SET_BASEURL: (state: any, baseUrl: string) => {
state.axiosBaseUrl = baseUrl
}
}
const actions = {
getConfigJson(context: { commit: Commit }) {
return new Promise((resolve, reject) => {
axios.get("../../../public/serverconfig.json").then((result: any) => {
context.commit('SET_BASEURL', result.data.ApiUrl)
// resolve 改变promise对象的状态为成功
resolve(result.data);
})
.catch((error: any) => {
// reject 改变promise对象的状态为失败
reject(error)
})
})
}
}
user.ts 来存储 用户信息以及token
getter.ts 引入modules文件夹下的所有存储
const getters = {
axiosBaseUrl: (state: any) => state.common.axiosBaseUrl
};
export default getters
②. store-> index.ts 中,引入 getters.ts 和modules 下的所有ts文件
import { createStore } from "vuex";
import getters from "./getter";
// 动态引入模块文件
// require.context('./modules', true, /\.ts$/)
// require.context('读取的文件路径',是否循环读取子目录,文件匹配的正则)
const modulesFiles = require.context('./modules', true, /\.ts$/)
export function isValidKey(key: string | number | symbol, object: object): key is keyof typeof object {
return key in object
}
const modules = modulesFiles.keys().reduce((modules: any, modulePath) => {
// set './app.js' => 'app'
const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
const value = modulesFiles(modulePath)
modules[moduleName] = value.default;
return modules
}, {})
export default createStore({
modules,
getters
});
axios 封装
axios->新建文件夹config
config->新建 types.ts
/**
* request配置
*/
export interface ConfigOptions {
result_code: any
default_headers: any
request_timeout: any
}
config->新建index.ts
/**
* request全局配置
*/
import { ConfigOptions } from './types'
const config: ConfigOptions = {
/**
* 接口成功返回状态码
*/
result_code: '0000',
/**
* 接口请求超时时间
*/
request_timeout: 15000,
/**
* 默认接口请求类型
* 可选值:application/x-www-form-urlencoded multipart/form-data
*/
default_headers: 'application/json'
};
export default config
axios->request.ts
import store from "@/store";
import axios, { AxiosError, AxiosInstance, AxiosResponse, InternalAxiosRequestConfig } from "axios";
import config from "./config";
import qs from 'qs'
import { ElMessage } from "element-plus";
import { reactifyObject } from "@vueuse/shared";
// 创建axios实例
const service: AxiosInstance = axios.create({
timeout: config.request_timeout // 请求超时时间
})
// request 拦截器
service.interceptors.request.use(
async (config: InternalAxiosRequestConfig) => {
config.url = (store.getters.axiosBaseUrl ? store.getters.axiosBaseUrl : (await store.dispatch('common/getConfigJson')).ApiUrl) + config.url
if (config.method === 'post' && config.headers ? config.headers['Content-Type'] === 'application/x-www-form-urlencoder' : '') {
// post方法的数据序列化
config.data = qs.stringify(config.data)
}
return config
},
(error: AxiosError) => {
console.log(error)
Promise.reject(error)
}
)
// response 拦截器
service.interceptors.response.use(
(response: AxiosResponse) => {
let res: any = response.data
// 改变登录状态
store.dispatch('loading/hideloader')
if (res && res.code == -100) {
// 登录超时
ElMessage({
showClose: true,
message: `登录超时`,
type: 'error'
})
// 改变token以及用户信息 (调用store/user 里的resetToken方法)
store.dispatch('user/resetToken')
location.reload()
} else {
return res
}
},
(error: AxiosError) => {
// 改变登录状态
store.dispatch('loading/hideloader')
ElMessage({
showClose: true,
message: error.message,
type: 'error'
})
return Promise.reject(error)
}
)
export default service
axios->index.ts
import store from "@/store"
import { getToken } from "@/utils/auth"
import { AxiosPromise, ResponseType } from "axios"
import request from './request'
import config from "./config"
const { default_headers } = config
interface Config {
params?: any
data?: any
url: string
method: 'get' | 'post' | 'delete' | 'put'
headersType?: string
responseType?: ResponseType
}
function fetch({ url, method, params, data, headersType, responseType }: Config): AxiosPromise {
return request({
url: url,
method,
params,
data,
responseType: responseType,
headers: {
'Content-Type': headersType || default_headers,
token: store.getters.token ? store.getters.token : getToken()
}
})
}
export {
fetch
}
接口封装
src->Api->user.ts
import { fetch } from "@/axios"
interface PropsData {
params?: any
data?: any
}
export const login = ({ data }: PropsData): any => {
return fetch({ url: '/Login', method: 'post', data })
}
export const userInfo = ({ params }: PropsData): any => {
return fetch({ url: '/userInfo', method: 'get', params })
}