前端页面数据加载添加loading效果
具体实现
全局loading配置
1 再src/componennts/Spinner下面建立一个index.vue
2 再utils下面tools.js
3 再utils下面建议一个request.js 封装的axios请求
4 修改app.vue
前端页面数据加载添加loading效果在前端上传文件或者加载数据的时候会有一段等待时间,如果加上一个loading效果会减轻用户等待的枯燥,这里就来记录学习一下如何实现loading效果。
效果大致如下,样式我们是可以自定义的。
具体实现let thisContent = this;
let loading = thisContent.$loading({
lock: true,
text: '上传中,请稍候...',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.5)'
})
// 中间进行一系列的操作
// 上传成功后关闭loading, 并显示上传成功
loading.close();
thisC.$message('上传文件成功');
这样一个简单的loading效果就实现了。
全局loading配置请求的时候 需要一个全局loading来拦截 若是页面单独引用的话 就有点繁琐了 所以需要再全局封装一个 此时就要明白 再哪里封装了 先考虑一下 为什么要用
一方面是为了防止重复操作
另一方面是为了一个加载的效果能够更明显
所以 再请求的时候加 就能联想到axios拦截器的位置处理了 话不多说 开始撸代码 全程copy就行了
1 再src/componennts/Spinner下面建立一个index.vue<template>
<div class="loading-page bg-opacity" :style="{display:hide?'none':'block'}">
<div class="dark" @dblclick="close">
<div class="la-ball-spin-clockwise la-2x">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
hide: true
}
},
methods: {
close() {
document.querySelector('.loading-page').style.display = 'none';
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
.show {
display: block;
}
.hide {
display: none;
}
.loading-page {
background: rgba(0, 0, 0, .65);
display: none;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
min-height: 100%;
min-width: 100%;
transition: all 1s;
z-index: 20000;
&.hide {
display: none;
}
&.bg-opacity {
background: rgba(0, 0, 0, 0);
}
.dark {
width: 100px;
height: 100px;
border-radius: 10px;
background: rgba(0, 0, 0, .65);
position: absolute;
top: 40%;
left: 50%;
margin-left: -50px;
text-align: center;
img {
width: 70px;
height: 70px;
margin-top: 15px;
}
}
}
.la-ball-spin-clockwise{
width: 64px;
height: 64px;
margin-top: 18px;
margin-left: 18px;
display: block;
font-size: 0;
color: #fff;
position: relative;
box-sizing: border-box;
animation-play-state: running;
}
.la-ball-spin-clockwise>div{
width: 16px;
height: 16px;
margin-top: -8px;
margin-left: -8px;
position: absolute;
border-radius: 100%;
animation: ball-spin-clockwise 1s infinite ease-in-out;
display: inline-block;
float: none;
background-color: currentColor;
border: 0 solid currentColor;
animation-play-state: running;
}
.la-ball-spin-clockwise>div:nth-child(1){
top: 5%;
left: 50%;
webkit-animation-delay: -.875s;
-moz-animation-delay: -.875s;
-o-animation-delay: -.875s;
animation-delay: -.875s;
}
.la-ball-spin-clockwise>div:nth-child(2) {
top: 18.1801948466%;
left: 81.8198051534%;
-webkit-animation-delay: -.75s;
-moz-animation-delay: -.75s;
-o-animation-delay: -.75s;
animation-delay: -.75s;
}
.la-ball-spin-clockwise>div:nth-child(3) {
top: 50%;
left: 95%;
-webkit-animation-delay: -.625s;
-moz-animation-delay: -.625s;
-o-animation-delay: -.625s;
animation-delay: -.625s;
}
.la-ball-spin-clockwise>div:nth-child(4) {
top: 81.8198051534%;
left: 81.8198051534%;
-webkit-animation-delay: -.5s;
-moz-animation-delay: -.5s;
-o-animation-delay: -.5s;
animation-delay: -.5s;
}
.la-ball-spin-clockwise>div:nth-child(5) {
top: 94.9999999966%;
left: 50.0000000005%;
-webkit-animation-delay: -.375s;
-moz-animation-delay: -.375s;
-o-animation-delay: -.375s;
animation-delay: -.375s;
}
.la-ball-spin-clockwise>div:nth-child(6) {
top: 81.8198046966%;
left: 18.1801949248%;
-webkit-animation-delay: -.25s;
-moz-animation-delay: -.25s;
-o-animation-delay: -.25s;
animation-delay: -.25s;
}
.la-ball-spin-clockwise>div:nth-child(7) {
top: 49.9999750815%;
left: 5.0000051215%;
-webkit-animation-delay: -.125s;
-moz-animation-delay: -.125s;
-o-animation-delay: -.125s;
animation-delay: -.125s;
}
.la-ball-spin-clockwise>div:nth-child(8) {
top: 18.179464974%;
left: 18.1803700518%;
-webkit-animation-delay: 0s;
-moz-animation-delay: 0s;
-o-animation-delay: 0s;
animation-delay: 0s;
}
@-webkit-keyframes ball-spin-clockwise{
0%,100%{
opacity:1;
-webkit-transform:scale(1);
transform:scale(1)}
20%{
opacity:1
}
80%{
opacity:0;
-webkit-transform:scale(0);
transform:scale(0)
}
}
@-moz-keyframes ball-spin-clockwise{
0%,100%{
opacity:1;
-moz-transform:scale(1);
transform:scale(1)
}
20%{
opacity:1
}
80%{
opacity:0;
-moz-transform:scale(0);
transform:scale(0)
}
}
@-o-keyframes ball-spin-clockwise{
0%,100%{
opacity:1;
-o-transform:scale(1);
transform:scale(1)
}
20%{
opacity:1
}
80%{
opacity:0;
-o-transform:scale(0);
transform:scale(0)
}
}
@keyframes ball-spin-clockwise{
0%,100%{
opacity:1;
-webkit-transform:scale(1);
-moz-transform:scale(1);
-o-transform:scale(1);
transform:scale(1)
}
20%{
opacity:1
}
80%{
opacity:0;
-webkit-transform:scale(0);
-moz-transform:scale(0);
-o-transform:scale(0);transform:scale(0)
}
}
</style>
2 再utils下面tools.js
class Msg {
static loading() {
document.querySelector('.loading-page').style.display = 'block';
}
static hideLoading() {
document.querySelector('.loading-page').style.display = 'none';
}
}
export {
Tools,
Msg
}
3 再utils下面建议一个request.js 封装的axios请求
import axios from 'axios'
import qs from 'qs'
import { MessageBox, Message } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'
import router from '@/router'
import {Msg} from '@/utils/tools';
import { removeToken } from '@/utils/auth'
var allResquest = 0;
// create an axios instance
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API, // api 的 base_url
withCredentials: true, // 跨域请求时发送 cookies
paramsSerializer: params => { // 查询字符串中的数组不使用方括号
return qs.stringify(params, { indices: false })
},
timeout: 15000 // request timeout
})
// request interceptor
service.interceptors.request.use(
config => {
if (store.getters.token) {
config.headers['Authorization'] = 'Bearer ' + getToken()
config.headers['filterMode'] = localStorage.getItem('dataType')
}
config.headers['project'] = "csr"
allResquest = allResquest + 1;
if (config.mask !== true) {
Msg.loading()
}
return config
},
error => {
return Promise.reject(error)
}
)
// response interceptor
service.interceptors.response.use(
/**
* If you want to get information such as headers or status
* Please return response => response
*/
/**
* 下面的注释为通过在response里,自定义code来标示请求状态
* 当code返回如下情况则说明权限有问题,登出并返回到登录页
* 如想通过 XMLHttpRequest 来状态码标识 逻辑可写在下面error中
* 以下代码均为样例,请结合自生需求加以修改,若不需要,则可删除
*/
response => {
allResquest = allResquest - 1;
const res = response.data;
if (response.status === 200) {
if (allResquest === 0) {
Msg.hideLoading();
}
// 50008 系统无此账号
// 50010 账号禁用
// 50012 账号或密码错误
// 50013 主账号被禁用,禁止登录
// 50014 token失效
// 50015 登录失败,无操作权限,请联系系统管理员!
// 50016 验证码错误
// 429 限流 服务器拥挤,请稍后再试
// -999 未知错误
// 403 无权限
if (res.code === 50008 || res.code === 50010 || res.code === 50012 || res.code === 50013 ||
res.code === 50016 || res.code === 50015 || res.code === 429 || res.code === -999 || res.code === 403 || res.code === 500) {
Message({
message: res.msg || 'error',
type: 'error',
duration: 5 * 1000,
offset: 0
})
return Promise.reject(res.msg || 'error')
} else if (res.code === 50014) {
if (store.getters.token) {
removeToken()
}
MessageBox.alert( res.msg,'错误提示', {
confirmButtonText: '确定',
callback: action => {
store.dispatch('logout')
router.push(`/login`)
}
})
return false
}
return res
}
},
error => {
allResquest = allResquest - 1;
Msg.hideLoading();
Message({
message: '服务拥挤,请稍后重试!',
type: 'error',
duration: 5 * 1000
})
return Promise.reject(error)
}
)
export default service
4 修改app.vue
<template>
<div id="app">
<router-view />
<Spinner></Spinner>
</div>
</template>
<script>
import Spinner from '@/components/Spinner'
export default {
name: 'App',
components: {
Spinner
}
}
</script>
<style>
</style>
以上为个人经验,希望能给大家一个参考,也希望大家多多支持易知道(ezd.cc)。