JS實用技巧實現(xiàn)loading加載示例詳解
防抖節(jié)流自定義指令
一、問題現(xiàn)象
操作系統(tǒng)流程時,網(wǎng)速過慢,點擊【按鈕】,頁面沒有及時反應;用戶感知不到,再次點擊按鈕,系統(tǒng)流程報錯。
二、想法
控制按鈕操作時的頻繁接口調(diào)用,通過防抖操作進行處理
三、實現(xiàn)
第一步:封裝自定義指令v-debounce
import Vue from 'vue';
//按鈕防抖動指令
Vue.directive('debounce', {
inserted(el, binding) {
el.addEventListener('click', () => {
if (!el.disabled) {
el.disabled = true;
setTimeout(() => {
el.disabled = false;
}, binding.value || 3 * 1000); // 三秒之內(nèi)點擊不會觸發(fā)接口調(diào)用
}
});
},
});
第二步:在main.js文件中引入文件
import '@/utils/directives.js';
第三步:項目的template中使用
<el-button type="primary" class="change-btns" @click="sendCode()" v-debounce>發(fā)送驗證碼</el-button>
loading加載
考慮到項目本身可能已經(jīng)進入尾聲,再應用自定義指令的話,需要耗費時間,逐一排查按鈕操作,費時費力。
一、想法
想要減少時間,肯定需要統(tǒng)一配置處理,考慮到控制接口的頻繁調(diào)用和操作頻繁等問題,或許通過頁面整體不可點擊的方式進行處理,那就是接口調(diào)用時控制頁面加載。
二、實現(xiàn)
- 首先寫一個loading.vue組件
<!--
* @Author: Winter_Bear
* @Date: 2023-03-25 16:18:16
* @LastEditors: zh
* @LastEditTime: 2023-03-25 16:55:18
* @Description: loading組件
-->
<template>
<div v-if="visable" class="loaidng">
<transition name="animation">
<div class="load">
<img alt="" class="img" src="@/assets/image/loading.png" />
</div>
</transition>
</div>
</template>
<script>
export default {
data() {
return {
visable: false,
};
},
};
</script>
<style scoped>
.loaidng {
width: 100% !important;
height: 100% !important;
display: -webkit-flex !important; /* 新版本語法: Chrome 21+ */
display: -webkit-box !important; /* 老版本語法: Safari, iOS, Android browser, older WebKit browsers. */
display: -moz-box !important; /* 老版本語法: Firefox (buggy) */
display: -ms-flexbox !important; /* 混合版本語法: IE 10 */
display: flex !important;
justify-content: center !important;
align-items: center !important;
position: fixed !important;
top: 0 !important;
right: 0 !important;
bottom: 0 !important;
left: 0 !important;
background: rgba(0, 0, 0, 0);
color: #282828;
font-size: 20px;
z-index: 999999;
}
.load {
background-clip: text;
-webkit-position: relative !important;
position: relative !important;
}
.img {
width: 75px;
animation: rotation 5s linear infinite;
animation: rotation 2s linear infinite;
-moz-user-select: -moz-none;
-khtml-user-select: none;
-webkit-user-select: none;
-o-user-select: none;
user-select: none;
}
.no-scroll {
height: 100vh;
}
.no-scroll > * {
position: sticky;
top: 0;
}
@keyframes rotation {
0% {
-webkit-transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
}
}
</style>
- 封裝loading.js文件
import Loading from './index.vue';
//先創(chuàng)建一個空實例
let instance = null;
let winX = null;
let winY = null;
window.addEventListener('scroll', function () {
if (winX !== null && winY !== null) {
window.scrollTo(winX, winY);
}
});
function disableWindowScroll() {
winX = window.scrollX;
winY = window.scrollY;
}
function enableWindowScroll() {
winX = null;
winY = null;
}
export default {
install(Vue) {
if (!instance) {
//構(gòu)造器 /子類
let MyLoading = Vue.extend(Loading);
instance = new MyLoading({
//創(chuàng)建一個div,并掛載上去
el: document.createElement('div'),
});
document.body.appendChild(instance.$el);
}
//自定義一些方法,操作loading的顯示與隱藏關
let customMethods = {
async start() {
console.log(instance);
instance.visable = true;
disableWindowScroll();
var mo = function (e) {
passive: false;
};
},
finish() {
instance.visable = false;
enableWindowScroll();
var mo = function (e) {
passive: false;
};
},
};
//掛載到自定義方法vue示例上
if (!Vue.$loading) {
Vue.$loading = customMethods;
//掛載到原型上
Vue.prototype.$loading = Vue.$loading;
} else {
console.log('$loading方法已被占用');
}
},
};
3.在main.js中掛載到全局Vue的原型上
import $loading from '@/components/loading/loading.js'; Vue.use($loading);
- 在request.js接口請求和響應攔截時做處理
import Vue from 'vue';
import axios from 'axios';
import store from '@/store';
import router from '@/router';
import messageup from './resetMessage.js';
import commonService from '@/api/common.js';
import storage from '@/utils/storage';
import { setToken, setRefreshToken } from '@/utils/auth.js';
const service = axios.create({
baseURL: process.env.VUE_APP_appBaseUrl,
// 跨域請求時是否需要使用憑證
withCredentials: false,
// 請求 1000s 超時
timeout: 1000 * 60 * 60,
});
let loadingSum = 0;
let isRefreshing = false; // 標記是否正在刷新 token, 防止多次刷新token
let requests = []; // 存儲待重發(fā)請求的數(shù)組(同時發(fā)起多個請求的處理)
// 請求攔截器
service.interceptors.request.use(
(config) => {
loadingSum++;
if (loadingSum == 1) {
Vue.$loading.start();
}
let EnterpriseToken = '';
storage.get('CLIENTID', (data) => {
EnterpriseToken = data;
});
if (EnterpriseToken) {
config.headers.EnterpriseToken = EnterpriseToken;
}
return config;
},
(error) => {
messageup({
message: '服務異常!',
type: 'error',
showClose: true,
duration: 0,
});
return Promise.resolve(error);
},
);
// 響應攔截器
service.interceptors.response.use(
(response) => {
let config = response.config;
let url = response.config.url;
const code = response.data.code;
loadingSum--;
if (loadingSum == 0) {
Vue.$loading.finish();
}
if (['701', '702'].includes(code)) {
storage.removeAll();
router.replace('/sign').catch((err) => err);
messageup({
message: response.data.message,
type: 'error',
});
return;
} else if (code == '801') {
//這部分屬于強制登錄的邏輯狀態(tài)處理
if (!isRefreshing) {
loadingSum++;
if (loadingSum == 1) {
Vue.$loading.start();
}
isRefreshing = true;
let getRefreshToken = '';
storage.get('REFCLIENTID', (data) => {
getRefreshToken = data;
});
if (getRefreshToken) {
return new Promise((resolve, reject) => {
let data = {
refreshToken: getRefreshToken,
};
commonService
.refreshToken(data)
.then((res) => {
if (res && res.data && res.data.code == '200') {
const { clientid, refreshid } = res.data.data;
setToken(clientid);
setRefreshToken(refreshid);
config.headers.EnterpriseToken = clientid;
// token 刷新后將數(shù)組的方法重新執(zhí)行
requests.forEach((cb) => cb(clientid));
requests = []; // 重新請求完清空
resolve(service(config));
} else {
requests = [];
storage.removeAll();
router.replace('/sign').catch((err) => err);
}
})
.catch((err) => {
return Promise.reject(err);
})
.finally(() => {
isRefreshing = false;
loadingSum--;
if (loadingSum == 0) {
Vue.$loading.finish();
}
});
});
} else {
loadingSum--;
if (loadingSum == 0) {
Vue.$loading.finish();
}
}
} else {
// 返回未執(zhí)行 resolve 的 Promise
return new Promise((resolve) => {
// 用函數(shù)形式將 resolve 存入,等待刷新后再執(zhí)行
requests.push((token) => {
config.headers.EnterpriseToken = token;
resolve(service(config));
});
});
}
} else {
return response;
}
},
(error) => {
loadingSum--;
if (loadingSum == 0) {
Vue.$loading.finish();
}
messageup({
message: error.message,
type: 'error',
showClose: true,
duration: 0,
});
return Promise.reject(error);
},
);
export default {
post(url, data = {}, headers = {}) {
return new Promise((resolve, reject) => {
service.post(url, data, headers).then(
(response) => {
resolve(response);
},
(err) => {
reject(err);
},
);
});
},
get(url, params = {}, headers = {}) {
return new Promise((resolve, reject) => {
service
.get(url, {
params: params,
headers: headers,
})
.then((response) => {
resolve(response);
})
.catch((err) => {
reject(err);
});
});
},
when(arry = []) {
if (arry.length <= 1) {
return arry[0];
} else {
let arr = [];
let length = arry.length;
for (let i = 0; i < length; i++) {
arr.push('res' + i);
}
return new Promise((resolve, reject) => {
axios.all(arry).then(
axios.spread((...arr) => {
resolve(arr);
}),
);
});
}
},
};
總結(jié)
axios攔截應用loading的時機:
1.請求攔截時統(tǒng)計所有接口請求的次數(shù),逐次累計;接口可能一次調(diào)很多個,但是僅首次調(diào)用時出現(xiàn)loading,后面再有接口調(diào)用時,就不再出現(xiàn)。
2.響應攔截時統(tǒng)一也會統(tǒng)計所有接口請求次數(shù),逐次累減;直到最終接口不再調(diào)用時,停止loading效果。
3.單純響應攔截過程中存在累計和累減;801登錄態(tài)強制更新時也同樣存在累計和累減。
以上就是JS實用技巧實現(xiàn)loading加載示例詳解的詳細內(nèi)容,更多關于JS loading加載技巧的資料請關注腳本之家其它相關文章!
相關文章
Vue.js React與Angular流行前端框架優(yōu)勢對比
這篇文章主要為大家介紹了Vue.js React與Angular流行前端框架優(yōu)勢對比,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-03-03
JS常用正則表達式超全集(密碼強度校驗,金額校驗,IE版本,IPv4,IPv6校驗)
網(wǎng)上有很多關于JS常用正則表達式的文章很全但今天為大家分享一些最新,且非常有用的正則表達式其中有密碼強度校驗,金額校驗,IE版本,IPv4,IPv6校驗等2020-02-02

