这是我参与更文挑战的第11天,活动详情查看: 更文挑战 !
? 概论
Loading是每个项目中必不可少的组件之一,它除了可以提升用户等待体验外,也可以起到防止误操作、事件防抖的作用,其形态也有很多种:组件内loading、按钮loading以及全局loading。
全局loading往往应该伴随着异步请求出现:请求开始时loaidng展示,请求结束时loading消失。知道这一基本需求外,我们就来一起封装一个基于请求的全局loading。
? 组件准备
首先准备好我们的loading组件,这个组件与大家常用的自定义组件并无二致。此阶段有两个要点:
1. 组件cursor使用not-allowed,以防事件穿透;
2. 组件样式的层级一定要够高,以免无法遮住所有元素;
复制代码
<!--index.vue-->
<template>
<div class="global-box">
<div class="wrap">
<div class="loading">
<div class="bounceball"></div>
<div class="text">LOADING</div>
</div>
</div>
</div>
</template>
<script>
export default {};
</script>
<style lang="less" scoped>
@import './index.less';
</style>
复制代码
//index.less
@width: 15px;
@height: 15px;
@bounce_height: 30px;
.global-box {
overflow: hidden;
position: absolute;
top: 0;
left: 0;
z-index: 9999;
width: 100vw;
height: 100vh;
background-color: rgba(0, 0, 0, 0.3);
cursor: not-allowed;
}
.wrap {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.text {
display: inline-block;
margin-left: 5px;
color: #ff4600;
}
.bounceball {
display: inline-block;
position: relative;
margin-right: 10px;
width: @width;
height: 37px;
&::before {
display: block;
position: absolute;
top: 0;
border-radius: 50%;
width: @width;
height: @height;
background-color: #ff4600;
transform-origin: 50%;
animation: bounce 500ms alternate infinite ease;
content: '';
}
}
@keyframes bounce {
0% {
top: @bounce_height;
border-radius: 60px 60px 20px 20px;
height: 5px;
transform: scaleX(2);
}
35% {
border-radius: 50%;
height: @height;
transform: scaleX(1);
}
100% {
top: 0;
}
}
复制代码
可以将其作为组件直接挂载在页面上,看看现在的效果:
? 挂载插件
挂载插件是该次封装流程的关键,这一过程中的总体思想是:
打开Loading,将Loading插件挂载到页面上;
关闭Loading,也就是将Loading插件从页面上卸载。
复制代码
道理很简单,直接上实践。
//mountLoading.js
import Vue from 'vue';
import Loading from './index';
const LoadingConstructor = Vue.extend(Loading);//定义Loading的构造器
const LoadingInstance = new LoadingConstructor({
el: document.createElement('div'),
});//创建实例
const loading = {
show() {
// 显示方法:挂载实例到body上
document.body.appendChild(LoadingInstance.$el);
},
hide() {
// 隐藏方法:从body上写在实例
document.body.removeChild(LoadingInstance.$el);
},
};
//创建Loading插件
export default {
//插件是一个对象时,必须提供 install 方法
install() {
//绑定$loading
!Vue.$loading && (Vue.$loading = loading);
//全局混入
Vue.mixin({
created() {
this.$loading = Vue.$loading;
},
});
},
};
复制代码
//main.js
import Vue from 'vue';
import App from './App.vue';
import router from './router';
import Loading from './loading/mountLoading';
Vue.use(Loading); // 使用loading插件
Vue.config.productionTip = false;
new Vue({
router,
render: (h) => h(App),
}).$mount('#app');
复制代码
此时loading插件已挂载成功,在页面中使用this.$loading.show()
或this.$loading.hide()
可成功改变loading状态。
? 请求跟随
这一步主要是利用了axios的拦截器,总体思想:
请求拦截器中打开loading;
响应拦截器中关闭loading。
复制代码
//request.js
import axios from 'axios';
import Vue from 'vue';
const instance = axios.create({
baseURL,
timeout: 30000,
});
// 请求拦截器
instance.interceptors.request.use((config) => {
Vue.$loading.show();
return config;
});
// 响应拦截器
instance.interceptors.response.use(
(res) => {
Vue.$loading.hide();
return res;
},
(err) => {
console.log('err: ', err);
Vue.$loading.hide();
},
);
export default instance;
复制代码
? 结语
铁汁们,你学会了吗??
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END