摘要
对于页面加载,网络请求等待,为了增强用户体验,往往会出现一个loading加载效果,相对减少用的焦虑感,那怎样去实现这样一个组件呢,可以用css的帧动画,也可以使用canvas画出这样一个动图。
本文将以css帧动画的形式实现loading加载效果
涉及的图片形式如下
1.采用css动画完成,keyframes定义0-100%的动画区间,每一个百分比运行的距离,一步完成所有的帧,无限循环,这种太过于冗余,得不偿失,不建议使用
// loading组件
<template>
<div class="loading-wrap" v-show="show">
<div class="loading">
<div class="img"></div>
</div>
</div>
</template>
<script>
export default {
name: 'ModalLoading',
data() {
return {
show: false
};
}
};
</script>
<style lang="scss" scoped>
@keyframes anima {
0.0000% {
background-position: 0px 0;
}
2.8571% {
background-position: -120px 0;
}
5.7143% {
background-position: -240px 0;
}
8.5714% {
background-position: -360px 0;
}
11.4286% {
background-position: -480px 0;
}
14.2857% {
background-position: -600px 0;
}
17.1429% {
background-position: -720px 0;
}
20.0000% {
background-position: -840px 0;
}
22.8571% {
background-position: -960px 0;
}
25.7143% {
background-position: -1080px 0;
}
28.5714% {
background-position: -1200px 0;
}
31.4286% {
background-position: -1320px 0;
}
34.2857% {
background-position: -1440px 0;
}
37.1429% {
background-position: -1560px 0;
}
40.0000% {
background-position: -1680px 0;
}
42.8571% {
background-position: -1800px 0;
}
45.7143% {
background-position: -1920px 0;
}
48.5714% {
background-position: -2040px 0;
}
51.4286% {
background-position: -2160px 0;
}
54.2857% {
background-position: -2280px 0;
}
57.1429% {
background-position: -2400px 0;
}
60.0000% {
background-position: -2520px 0;
}
62.8571% {
background-position: -2640px 0;
}
65.7143% {
background-position: -2760px 0;
}
68.5714% {
background-position: -2880px 0;
}
71.4286% {
background-position: -3000px 0;
}
74.2857% {
background-position: -3120px 0;
}
77.1429% {
background-position: -3240px 0;
}
80.0000% {
background-position: -3360px 0;
}
82.8571% {
background-position: -3480px 0;
}
85.7143% {
background-position: -3600px 0;
}
88.5714% {
background-position: -3720px 0;
}
91.4286% {
background-position: -3840px 0;
}
94.2857% {
background-position: -3960px 0;
}
97.1429% {
background-position: -4080px 0;
}
100.0000% {
background-position: -4200px 0;
}
}
.loading-wrap {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 999999;
background: rgba(24, 26, 36, 1);
.loading {
position: absolute;
top: 50%;
left: 50%;
width: 260px;
height: 140px;
border-radius: 10px;
background: rgba(0, 0, 0, 0.7);
transform: translate3d(-50%, -50%, 0);
text-align: center;
line-height: 140px;
.img {
position: absolute;
top: 50%;
left: 50%;
width: 120px;
height: 65px;
transform: translate3d(-50%, -50%, 0);
background: url('./images/loading.png') no-repeat;
background-size: 3600% 100%;
animation: anima 2s steps(1) infinite;
}
}
}
</style>
2.也是采用css动画,图片有36张,就相当于是36帧,但是注意动画是从0开始的,实际看到第36张图的其实点是35的结尾,所以steps(35),keyframes定义100%的即可
<template>
<div class="loading-wrap" v-show="show">
<div class="loading-com loading" :class="{ 'bg-com': needBg }" v-if="true">
<div class="img"></div>
<p class="txt">正在加载中...</p>
</div>
<div v-else class="loading-com loading-other" :class="{ 'bg-com': needBg }">
<div class="img"></div>
</div>
</div>
</template>
<script>
export default {
name: 'ModalLoading',
data() {
return {
show: false,
needBg: false
};
}
};
</script>
<style lang="scss" scoped>
@keyframes anima {
100% {
background-position: -3500px 0;
}
}
.loading-wrap {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 999999;
background: rgba(24, 26, 36, 1);
.loading-com {
position: absolute;
top: 50%;
left: 50%;
width: 260px;
height: 140px;
border-radius: 10px;
transform: translate3d(-50%, -50%, 0);
text-align: center;
}
.bg-com {
background: rgba(0, 0, 0, 0.7);
}
.loading {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.txt {
margin-top: 22px;
font-size: 28px;
font-weight: 400;
color: rgba(103, 106, 125, 1);
}
}
.img {
width: 100px;
height: 54px;
background: url('./images/loading.png') no-repeat;
background-size: 3600% 100%;
animation: anima 1.5s steps(35) infinite;
}
.loading-other {
height: 80px;
width: 140px;
.img {
position: absolute;
top: 50%;
left: 50%;
transform: translate3d(-50%, -50%, 0);
}
}
}
</style>
3.其次就是封装成可以在任何地方调用的组件
/**
* 使用方法
* 显示loading 不是在实例化的组件中 Vue.showLoading() 如果是在vue的组件中使用则 this.$showLoading()
* 关闭loading 不是在实例化的组件中 Vue.closeLoading() 如果是在vue的组件中使用则 this.$closeLoading()
*/
import ModalLoading from './ModalLoading.vue';
let ModalLoad = {};
ModalLoad.install = function(Vue) {
// 在全局状态下只有一个实例 options = {}option = {}
let instance;
let defaultOptions = {
needBg: false // 默认不需要背景
};
// 在Vue的原型上扩展方法
Vue.showLoading = Vue.prototype.$showLoading = function(option) {
defaultOptions = Object.assign(defaultOptions, option);
// 实例化所引入的插件
const ModalLoadController = Vue.extend(ModalLoading);
// 判断当前实例是不是已经存在
if (!instance) {
// 实例化插件并挂在到某一个元素上
instance = new ModalLoadController({
el: document.createElement('div')
});
// 添加在body内
document.body.appendChild(instance.$el);
}
if (instance.show) return;
instance.show = true;
instance.needBg = defaultOptions.needBg;
};
Vue.closeLoading = Vue.prototype.$closeLoading = function() {
instance ? (instance.show = false) : '';
};
};
// 自动安装插件
if (typeof window != 'undefined' && window.Vue) {
// eslint-disable-next-line no-undef
Vue.use(ModalLoad);
}
// 导出对象
export default ModalLoad;
4.使用方式
// 引入
import ModalLoading from "./components/index";
Vue.use(ModalLoading);
// 使用
Vue.showLoading();
5.效果
关于css animation中的animation-timing-function的取值,比如文中提及的steps()函数,可以参考MDN web docs