前言
前期回顾
目录
我要实现什么效果?
-
全局封装一次!
-
项目中切换路由显示loading,
-
发起axios显示loading,
-
每个页面显示返回顶部
代码简单吗?
-
极简
念及此
- 正文开始
一、封装axiso前先配置环境变量
- 因为真实项目中需要不同环境测试的
第一步: 配置环境变量
在根目录新建三个文件
.env.development
NODE_ENV='development'
.env.production
NODE_ENV='production'
.env.staging
NODE_ENV='production'
完成!
第二步:封装axios
在src下新建newwork文件夹 并在里面新建4个文件
解释:
- api.js 封装的是api接口,在项目中大量用到接口不能分散写在各处、不易维护
- baseUrl.s 匹配环境变量 比如开发环境则使用线上接口,生产环境则使用生产接口
- http.js 创建axiso实例写入请求拦截响应拦截
- request.js 封装的是请求方法,在项目中大量用到接口,所以将请求方法也封装
正文:
一:先写baseUrl.js 匹配环境变量
let baseURL = "";
if (process.env.NODE_ENV === "development") {
// 开发环境 因为我这里写了配置跨域的重定路径所以是api 如下图
baseURL = "/api";
} else if (process.env.NODE_ENV === "production") {
// 正式环境 真正的上线网址 不是跨域别名路径,在network不显示
baseURL = "";
} else {
// 测试环境
baseURL = "";
}
export default baseURL;
二: 网址配好后写 http.js 创建axiso实例
import axios from "axios";
// 导入element-ElMessage 弹框
// import { ElMessage } from "element-plus";
// 导入配置的环境变量url
import baseURL from "./baseURL";
// 导入路由,没有this,使用路由实例跳转
import router from "../route/router.ts";
// 导入main全局配置文件
import app from "../../src/main";
// 开启loading
app.config.globalProperties.$loading.showLoading();
// 创建axios实例
const http = axios.create({
baseURL, //配置了跨域,起了别名api,在baseBUL用了别名,这里使用baseURL,配置在下面vue.config.js
timeout: 6000,
withDirectives: true, // 是否携带cookies
});
// 请求拦截
http.interceptors.request.use(
(config) => {
// 在请求发送之前做一些处理 config是axios的配置对象
// console.log(config);
// 携带token
config.headers["Authorization"] =
"Bearer " + JSON.parse(localStorage.getItem("remember_token")) || null;
// 配置完成将config返回
return config;
},
(err) => {
// 当请求失败时做一些处理 抛出错误
throw new Error(err);
}
);
// 响应拦截
http.interceptors.response.use(
(res) => {
// 在返回响应之前做一些处理 res是axios的配置对象
// console.log(res);
// 关闭loading
app.config.globalProperties.$loading.hideLoading();
// 根据后台状态码统一封装提示信息 就不需要在页面接口在单独写了
// 这里根据实际接口的嵌套情况和状态码来写 这里只是我的接口嵌套情况
let { status, msg } = res.data.meta;
//key = value status等于200就执行200下的代码 执行完break退出循环
switch (status) {
case 200:
ElMessage({
showClose: true,
message: msg,
type: "success",
});
break;
case 401:
ElMessage({
showClose: true,
message: "未授权",
type: "error",
});
// console.log(this);
// this是undefined所以引入路由;
router.push("/login"); //未授权跳转到login
break;
}
// 这里根据接口返回的数据嵌套结构来返回 比如我的接口返回的是{data:{message:{}}}
return res.data.message;
},
(err) => {
// 当响应失败时做一些处理 抛出错误
throw new Error(err);
}
);
// 导出 http实例 方便调用
export default http;
三:请求封装好了 封装请求方法 request.js
import http from "./http";
// post请求: 传参数没有明确规定使用params接受参数就是要使用data请求体接受,get请求要使用params接受
// put 也相当与post请求,如果报参数错误,就是接受参数的请求体错了post/put用data,get请求用params
function request({ method = 'get', url, data = {}, params = {} }) {
return http({
method,
url,
data,
params
})
}
export default request;
四:请求方法好了 封装api.js
// 导入请求的方法
// 不使用箭头函数
// export function home() {
// return request({ url: '/home', })
// }
import request from "./request";
// 用户登陆的接口 post请求使用data请求体 默认封装的get 如果是get请求不需要写methiod
export const login = (data) => request({ method: "post", url: '/login', data: data });
// 获取用户列表的接口 ,需要有默认参数. pagenum: 1,pagesize: 10,,所以要接收,
export const getUserList = (params) => request({ url: '/users', params });
// put请求修改用户id users/:uId/state/:type
export const getEdit = (data) => request({
method: "put",
data,
url: "users/" + data.uid + "/state/" + data.type,
})
export const order = () => request({ url: "/home/floordata" });
二:封装loading
在src下的 components 新建 俩个文件
loading.vue
<template>
<div id="loading" v-show="visible">
<div class="circle"></div>
<br />
疯狂加载中...
</div>
</template>
<script>
import { defineComponent, ref } from "vue";
export default defineComponent({
name: "Loading",
setup() {
// 控制组件的状态
let visible = ref(false);
// 显示组件
let showLoading = () => {
visible.value = true;
};
// 隐藏组件
let hideLoading = () => {
visible.value = false;
};
return { visible, showLoading, hideLoading };
},
});
</script>
<style scoped>
#loading {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
position: absolute;
top: 0;
left: 0;
z-index: 999;
display: flex;
align-items: center;
justify-content: center;
}
@keyframes loading {
0% {
transform: rotate(0);
}
50% {
transform: rotate(160deg);
}
100% {
transform: rotate(360deg);
}
}
.circle {
width: 45px;
height: 45px;
background-color: transparent;
border-radius: 50%;
border: 5px solid #528bee;
border-left-color: #ccc;
animation: loading 1s linear 1s infinite;
}
</style>
index.ts
- (因为我是ts项目所以.ts)
import { createApp } from "vue";
// 导入写好的Loading.vue文件
import Loading from "./Loading.vue";
export default {
loading: null,
/* 每当这个插件被添加到应用程序中时,如果它是一个对象,就会调用 install 方法。
如果它是一个 function,则函数本身将被调用。在这两种情况下——它都会收到两个参数:由 Vue 的 createApp 生成的 app 对象和用户传入的选项。 */
install(app) {
if (this.loading) {
// 防止多次载入
app.config.globalProperties.$loading = this.loading;
return;
}
// 创建Loading实例,用于挂载
let instance = createApp(Loading);
// 创建div元素装载Loading对象
let div = document.createElement("div");
let body = document.body;
// 导入body中
body.appendChild(div);
this.loading = instance.mount(div);
// 挂载vue身上
app.config.globalProperties.$loading = this.loading;
},
};
在main.ts引入index.ts
// 自定义loading组件 import Loading from "./components/MyLoading/index.ts"; app.use(Loading); export default app; // 这里导出app的目的,是为了在后面演示js文件中使用插件
封装完成,现在 在请求拦截前和路由跳转前 开启一下全局生效
http.js
router.ts
router.beforeEach((to, from, next) => { if (to.meta.loading) { app.config.globalProperties.$loading.showLoading(); next(); } else { next(); } }); router.afterEach((to, from) => { if (to.meta.loading) { app.config.globalProperties.$loading.hideLoading(); } });
封装请求loading完成
三:封装返回顶部
在src 的components 下新建 俩个文件
MyBackTop.vue
<template>
<el-backtop
style="width: 60px; height: 60px"
:bottom="50"
:visibility-height="1000"
/>
</template>
index.ts
import { createApp } from "vue";
import BackTop from "./MyBackTop.vue";
export default {
BackTop: null,
install(app) {
if (this.BackTop) {
app.config.globalProperties.$BackTop = this.BackTop;
return;
}
let instance = createApp(BackTop);
let div = document.createElement("div");
let body = document.body;
body.appendChild(div);
this.BackTop = instance.mount(div);
app.config.globalProperties.$BackTop = this.BackTop;
},
};
在main.ts引入index.ts
// 自定义回到顶部组件 import BackTop from "./components/MyBackTop/index.ts" app.use(BackTop); export default app; // 这里导出app的目的,是为了在后面演示js文件中使用插件
结语
目前为止我们实现了 axios封装 loading 封装 返回顶部封装 !本人亲测保证能用
最后祝大家2022越来越强