溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

JS怎么實(shí)現(xiàn)loading加載

發(fā)布時(shí)間:2023-05-11 15:27:53 來源:億速云 閱讀:253 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要講解了“JS怎么實(shí)現(xiàn)loading加載”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“JS怎么實(shí)現(xiàn)loading加載”吧!

防抖節(jié)流自定義指令

一、問題現(xiàn)象

操作系統(tǒng)流程時(shí),網(wǎng)速過慢,點(diǎn)擊【按鈕】,頁面沒有及時(shí)反應(yīng);用戶感知不到,再次點(diǎn)擊按鈕,系統(tǒng)流程報(bào)錯(cuò)。

二、想法

控制按鈕操作時(shí)的頻繁接口調(diào)用,通過防抖操作進(jìn)行處理

三、實(shí)現(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)點(diǎn)擊不會觸發(fā)接口調(diào)用
            }
        });
    },
});

第二步:在main.js文件中引入文件

import '@/utils/directives.js';

第三步:項(xiàng)目的template中使用

<el-button type="primary" class="change-btns" @click="sendCode()" v-debounce>發(fā)送驗(yàn)證碼</el-button>

loading加載

考慮到項(xiàng)目本身可能已經(jīng)進(jìn)入尾聲,再應(yīng)用自定義指令的話,需要耗費(fèi)時(shí)間,逐一排查按鈕操作,費(fèi)時(shí)費(fèi)力。

一、想法

想要減少時(shí)間,肯定需要統(tǒng)一配置處理,考慮到控制接口的頻繁調(diào)用和操作頻繁等問題,或許通過頁面整體不可點(diǎn)擊的方式進(jìn)行處理,那就是接口調(diào)用時(shí)控制頁面加載。

二、實(shí)現(xiàn)

  • 首先寫一個(gè)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)建一個(gè)空實(shí)例
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)建一個(gè)div,并掛載上去
        el: document.createElement('div'),
      });
      document.body.appendChild(instance.$el);
    }
    //自定義一些方法,操作loading的顯示與隱藏關(guān)
    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接口請求和響應(yīng)攔截時(shí)做處理

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,
  // 跨域請求時(shí)是否需要使用憑證
  withCredentials: false,
  // 請求 1000s 超時(shí)
  timeout: 1000 * 60 * 60,
});
let loadingSum = 0;
let isRefreshing = false; // 標(biāo)記是否正在刷新 token, 防止多次刷新token
let requests = []; // 存儲待重發(fā)請求的數(shù)組(同時(shí)發(fā)起多個(gè)請求的處理)
// 請求攔截器
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: '服務(wù)異常!',
      type: 'error',
      showClose: true,
      duration: 0,
    });
    return Promise.resolve(error);
  },
);
// 響應(yīng)攔截器
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') {
      //這部分屬于強(qiáng)制登錄的邏輯狀態(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);
          }),
        );
      });
    }
  },
};

感謝各位的閱讀,以上就是“JS怎么實(shí)現(xiàn)loading加載”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對JS怎么實(shí)現(xiàn)loading加載這一問題有了更深刻的體會,具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識點(diǎn)的文章,歡迎關(guān)注!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI