【前端】Vue项目:旅游App-(19)loading:网络请求时显示loading效果

文章介绍了如何在Vue项目中创建一个全局loading组件,并通过mainStore进行控制显示。在发送网络请求时自动显示loading,请求完成后隐藏。同时,实现了点击loading蒙板可取消请求的功能,并使用拦截器优化loading的显示逻辑。
摘要由CSDN通过智能技术生成

本项目博客总结:【前端】Vue项目:旅游App-博客总结

目标

在发送网络请求的时候显示loading:

在这里插入图片描述

过程与代码

loading效果

本App中任何一个地方发送网络请求都要显示loading效果,因此我们要把它封装在一个组件中。且在App.vue中引入。

css代码解释,此做法可以:

  • 让明确宽高的盒子垂直水平居中
  • 让无宽高的盒子填满父容器
  • 这里是第二种
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;

loading总代码:

<template>
    <div class="loading">
        <div class="bg">
            <img src="@/assets/img/home/full-screen-loading.gif" alt="">
        </div>
    </div>
</template>

<script setup>

</script>

<style lang="less" scoped>
.loading {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;

    // 蒙板颜色
    background-color: rgba(0, 0, 0, .2);

    // loading的效果会在任何效果之上
    z-index: 999;

    // 垂直水平居中
    display: flex;
    justify-content: center;
    align-items: center;

    .bg {
        background: url(@/assets/img/home/loading-bg.png) 0 0 /100% 100%;
        width: 104px;
        height: 104px;

        display: flex;
        justify-content: center;
        align-items: center;

        img {
            width: 70px;
            height: 70px;
            margin-bottom: 9px;
        }
    }

}
</style>

效果:背景有点灰色的地方就是蒙板

在这里插入图片描述

mainStore控制loading显示

我们的需求:在发送网络请求(简单来说就是加载数据)的时候显示loading。这样更加用户友好。

显然,App中很多页面都有可能要加载数据,因此我们需要把loading显示的控制放在一个地方统一管理。不难想到要放到store的mainStore中管理(上篇管理整个App时间设置的地方)。

useMainStore:

isLoading:false

html:

<div class="loading" v-if="mainStore.isLoading">

js:

import useMainStore from '../../store/modules/main';

const mainStore=useMainStore()

点击蒙板取消网络请求

这是一个常见的效果。

html:

<div class="loading" v-if="mainStore.isLoading" @click="loadingClick()">

js:

function loadingClick() {
    mainStore.isLoading = false
}

在网络请求处添加对loading的控制

我们的需求:在发送网络请求的时候显示loading。

而我们在代码中封装了网络请求的功能,很显然,我们可以在request中添加在对loading的控制,如:

request(config) {
 loadingStore.changeLoading(true);
 mainStore.isLoading = true
 return new Promise((resolve, reject) => {
   this.instance
     .request(config)
     .then((res) => {
       resolve(res.data);
       mainStore.isLoading = false
     })
     .catch((err) => {
       console.log("request err:", err);
       reject(err);
       mainStore.isLoading = false
     })
     .finally(() => {
       loadingStore.changeLoading(false);
     });
 });

在这里插入图片描述
在发送请求时显示loading,发送完或发送完都取消显示。

但是不推荐这样做,我们希望一个方法只做一个功能。这里推荐使用拦截器

拦截器 | Axios 中文文档 | Axios 中文网 (axios-http.cn)
axios 请求拦截器&响应拦截器 - 简书 (jianshu.com)

注意,拦截器是绑定在实例上的。我们要把它写在构造函数里。

constructor(baseURL) {
  this.instance = axios.create({
    baseURL,
    timeout: TIMEOUT,
  });

  this.instance.interceptors.request.use(config => {
    // 发送网络请求前要做的事
    mainStore.isLoading = true
    return config
  }, err => {
    // 发送网络请求失败要做的事
    return err
  })

  this.instance.interceptors.response.use(res => {
    // 响应成功要做的事
    mainStore.isLoading = false
    return res
  }, err => {
    // 响应失败要做的事
    mainStore.isLoading = false
    return err
  })
}

效果

发送网络请求时会显示loading,数据加载完后就消失。

总代码

修改或添加的文件

在这里插入图片描述

loading.vue

loading组件。

<template>
    <div class="loading" v-if="mainStore.isLoading" @click="loadingClick()">
        <div class="bg">
            <img src="@/assets/img/home/full-screen-loading.gif" alt="">
        </div>
    </div>
</template>

<script setup>
import useMainStore from '../../store/modules/main';

const mainStore = useMainStore()

function loadingClick() {
    mainStore.isLoading = false
}
</script>

<style lang="less" scoped>
.loading {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;

    // 蒙板颜色
    background-color: rgba(0, 0, 0, .2);

    // loading的效果会在任何效果之上
    z-index: 999;

    // 垂直水平居中
    display: flex;
    justify-content: center;
    align-items: center;

    .bg {
        background: url(@/assets/img/home/loading-bg.png) 0 0 /100% 100%;
        width: 104px;
        height: 104px;

        display: flex;
        justify-content: center;
        align-items: center;

        img {
            width: 70px;
            height: 70px;
            margin-bottom: 9px;
        }
    }

}
</style>

service/request/index

在网络请求的代码中添加请求拦截器和响应拦截器。

import axios from "axios";

import { useLoadingStore } from "@/store/modules/loading";
import useMainStore from "../../store/modules/main";
import { baseURL, TIMEOUT } from "./config";

const loadingStore = useLoadingStore();
const mainStore = useMainStore()

class HYRequest {
  constructor(baseURL) {
    this.instance = axios.create({
      baseURL,
      timeout: TIMEOUT,
    });

    this.instance.interceptors.request.use(config => {
      // 发送网络请求前要做的事
      mainStore.isLoading = true
      return config
    }, err => {
      // 发送网络请求失败要做的事
      return err
    })

    this.instance.interceptors.response.use(res => {
      // 响应成功要做的事
      mainStore.isLoading = false
      return res
    }, err => {
      // 响应失败要做的事
      mainStore.isLoading = false
      return err
    })
  }

  request(config) {
    loadingStore.changeLoading(true);
    return new Promise((resolve, reject) => {
      this.instance
        .request(config)
        .then((res) => {
          resolve(res.data);
        })
        .catch((err) => {
          console.log("request err:", err);
          reject(err);
        })
        .finally(() => {
          loadingStore.changeLoading(false);
        });
    });
  }

  get(config) {
    return this.request({ ...config, method: "get" });
  }

  post(config) {
    return this.request({ ...config, method: "post" });
  }
}

export default new HYRequest(baseURL);

store/modules/main

添加isLoading来控制loading的显示。

import { defineStore } from "pinia"

const startDay = new Date()
const endDay = new Date()
endDay.setDate(startDay.getDate() + 1)

const useMainStore = defineStore('main', {
    state: () => ({
        token:'',

        startDay:startDay,
        endDay:endDay,

        isLoading:false,
    }),
    actions: {

    }
})

export default useMainStore

App.vue

添加loading组件。

<template>
    <div class="app">
        <router-view/>
        <tab-bar v-if="!$route.meta.hideTabBar"></tab-bar>
        <loading/>
    </div>
</template>

<script setup>

import tabBar from './components/tab-bar/tab-bar.vue';
import loading from './components/loading/loading.vue';

import { useRoute } from 'vue-router'

const route=useRoute()

</script>

<style lang="less" scoped>

</style>

在这里插入图片描述

参考

css中 top, right, bottom, left设置为0有什么用?它和width:100%和height:100%有什么区别?

CSS Backgrounds(背景) | 菜鸟教程 (runoob.com)

拦截器 | Axios 中文文档 | Axios 中文网 (axios-http.cn)

axios 请求拦截器&响应拦截器 - 简书 (jianshu.com)

引用中提到了webpack-manifest-plugin,它是一个用于基于文件名的缓存清除配置的插件。简单来说,它可以生成一个资源清单,其中包含了所有JavaScript、css和其他资源的哈希命名。这个清单可以帮助webpack知道我们需要的资源在哪里。引用和引用中介绍了使用import()和await来异步加载模块的方法。通过这种方式,我们可以在模块加载完成后执行代码,以便在Vue实例化之前加载所需的组件。在这个例子中,我们可以看到使用import()加载Vue模块并创建Vue实例的示例代码。在引用中,我们还可以看到通过async/await来执行异步函数的示例代码。 根据提供的信息,我们可以看出,在D:\project\dev-app-one\frontend\ext\vue.config.js文件中发生了加载错误。具体的错误信息需要查看该文件的具体内容才能确定。可能的原因包括文件路径错误、模块加载错误或其他语法错误。您可以检查文件中的代码,以确定问题所在,并进行相应的修正。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [用于前端开发的webpack4配置[带注释]](https://blog.csdn.net/weixin_33936401/article/details/88031527)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

karshey

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值