vue数据未加载完成前显示loading遮罩

本文介绍了在Vue前后端分离项目中,如何通过CSS和JavaScript实现实时的loading遮罩,提高数据请求时的用户体验。通过提供和注入方法,使遮罩功能可在多个组件复用,并结合SSR策略,确保页面与数据的同步渲染。

目的

在前后端分离项目中,由于页面请求和数据请求并非同步,所以导致页面和数据不能同时渲染,因此在实际过程中往往采用SSR即服务端渲染或者请求数据时采用遮罩(加载中)的方式提升用户体验。
下面我将使用loading遮罩的方式实现更加友好的数据加载

参考

https://codepen.io/bartezic/pen/ByqeNq

效果

代码

  1. 在App.vue中添加一个<div>
<div>
    <div id="appLoading">
      <div class='lmask'></div>
    </div>
    <div id="app">
      <router-view v-if="isRouterAlive"/>
    </div>
  </div>
  1. 以下是CSS样式

.lmask {
  position: absolute;
  height: 100%;
  width: 100%;
  background-color: #000;
  bottom: 0;
  left: 0;
  right: 0;
  top: 0;
  z-index: 9999;;
  opacity: 0.4;
  &.fixed {
    position: fixed;
  }
  &:before {
    content: '';
    background-color: rgba(0,0,0,0);
    border: 5px solid rgba(0,183,229,0.9);
    opacity: .9;
    border-right: 5px solid rgba(0,0,0,0);
    border-left: 5px solid rgba(0,0,0,0);
    border-radius: 50px;
    box-shadow: 0 0 35px #2187e7;
    width: 50px;
    height: 50px;
    -moz-animation: spinPulse 1s infinite ease-in-out;
    -webkit-animation: spinPulse 1s infinite linear;

    margin: -25px 0 0 -25px;
    position: absolute;
    top: 50%;
    left: 50%;
  }
  &:after {
    content: '';
    background-color: rgba(0,0,0,0);
    border: 5px solid rgba(0,183,229,0.9);
    opacity: .9;
    border-left: 5px solid rgba(0,0,0,0);
    border-right: 5px solid rgba(0,0,0,0);
    border-radius: 50px;
    box-shadow: 0 0 15px #2187e7;
    width: 30px;
    height: 30px;
    -moz-animation: spinoffPulse 1s infinite linear;
    -webkit-animation: spinoffPulse 1s infinite linear;

    margin: -15px 0 0 -15px;
    position: absolute;
    top: 50%;
    left: 50%;
  }
}

@-moz-keyframes spinPulse {
  0% {
    -moz-transform:rotate(160deg);
    opacity: 0;
    box-shadow: 0 0 1px #2187e7;
  }
  50% {
    -moz-transform: rotate(145deg);
    opacity: 1;
  }
  100% {
    -moz-transform: rotate(-320deg);
    opacity: 0;
  }
}
@-moz-keyframes spinoffPulse {
  0% {
    -moz-transform: rotate(0deg);
  }
  100% {
    -moz-transform: rotate(360deg);
  }
}
@-webkit-keyframes spinPulse {
  0% {
    -webkit-transform: rotate(160deg);
    opacity: 0;
    box-shadow: 0 0 1px #2187e7;
  }
  50% {
    -webkit-transform: rotate(145deg);
    opacity: 1;
  }
  100% {
    -webkit-transform: rotate(-320deg);
    opacity: 0;
  }
}
@-webkit-keyframes spinoffPulse {
  0% {
    -webkit-transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(360deg);
  }
}

  1. 此时遮罩层显示,我们需要当App加载完成后取消遮罩层,即display: none
	document.getElementById('app').style.display = 'block';
	document.getElementById('appLoading').style.display = 'none';
  1. 如何在我们需要的地方调用呢
    我采用的方法是写一个loading和loaded函数,在分别在请求数据前和请求数据完成后调用,因为该功能可能会重复的使用,所以将其封装成为一个可以复用的模块
    在App.vue中写两个方法:
	provide() {
	    return {
	      loading: this.loading,
	      loaded: this.loaded
	    }
	  },
	  methods: {
		loading() {
		      document.getElementById('app').style.display = 'block';
		      document.getElementById('appLoading').style.display = 'block';
		},
	    loaded() {
	      document.getElementById('app').style.display = 'block';
	      document.getElementById('appLoading').style.display = 'none';
	    }
	  }
	

上面将这两个函数给暴露了出来,在我们需要的地方inject就好
5. 在需要使用的地方调用

export default {
  inject: ['loading', 'loaded'],
  name: "index",
  created() {
    this.getData()
  },
  methods: {
    getData() {
      this.loading()
      getUserInfo().then(res => {
        this.userInfo = res.data
      }).finally(() => {
        this.loaded()
      })
    }
  }
}
  1. 完成

总结

实现思路非常简单,就是请求数据之前将遮罩显示,加载数据完成后将遮罩隐藏,解决这个问题肯定有非常多的办法,如果你有更好的方法,请在评论区留言。

<think>嗯,用户想在Vue3项目中实现页面加载显示遮罩loading,加载完成后隐藏。我需要先回顾一下之关于Vue全局遮罩加载的引用内容。根据引用[1],他们用了ElementPlus的ElLoading服务,创建了startLoading和endLoading函数。然后引用[2]提到在需要的地方注入并使用这些方法,比如在created钩子中调用加载数据的方法,并在finally里结束loading。用户现在的问题是Vue3中的实现,可能需要考虑组合式API的用法。首先,我应该确认是否仍然使用ElementPlus的Loading组件,或者是否有其他库的选择。不过用户之的引用提到了Element Plus,所以可能倾向于这个方案。接下来,全局遮罩需要在页面加载显示,所以可能需要路由守卫或者顶层组件的生命周期钩子。不过如果数据加载是在特定组件中进行的,比如在created或onMounted时获取数据,那么在这些地方调用start和end方法更合适。 另外,用户可能希望全局管理loading状态,避免每个组件重复代码。可以考虑使用Vue3的provide/inject机制,或者一个全局状态管理工具如Pinia。但根据引用中的例子,他们用了inject,所以在Vue3中也可以沿用这种方式。需要注意,Vue3的组合式API中,setup函数替代了之的选项式API,所以可能需要将loading方法通过provide提供给子组件,子组件通过inject来获取。同时,异步请求可能在setup中使用async/await,但需要小心处理,因为setup同步执行,可能需要结合Suspense组件,但可能复杂。 另一个考虑是,如果页面切换时需要显示loading,可以使用路由守卫。在进入路由开启loading数据加载完成后关闭。但用户的问题可能更多指页面内的数据加载,而非路由切换。可能的步骤是:封装ElLoading成全局可用的函数,在需要的地方调用,比如在发起API请求start,在完成后end。同时,处理可能的多个同时请求,避免一个请求结束就关闭loading,应该用计数器或者队列来管理。不过用户的问题可能不需要这么复杂,简单的单个请求的情况。所以基础方案是创建loading服务,在组件初始化时调用start,数据加载后调用end。例如,在setup中使用onMounted钩子,或者在scriptsetup中使用async。另外,错误处理需要考虑,无论成功还是失败都要关闭loading,所以用finally方法。总结步骤:1.封装loading函数;2.在组件中调用,比如在onMounted或created时开始,数据获取完成后结束;3.使用provide/inject或者直接导入封装好的函数。可能的问题:多个组件同时触发loading的情况,是否需要全局状态。但根据用户需求,可能基本场景足够,所以先提供基础实现,再提到优化点如全局状态管理。</think>在Vue3中实现页面加载遮罩效果,可通过以下步骤实现: ### 一、基础实现方案 1. **封装全局Loading服务** ```javascript // utils/loading.js import { ElLoading } from 'element-plus' let loadingInstance let needLoadingRequestCount = 0 // 请求计数器 export const showLoading = () => { if (needLoadingRequestCount === 0) { loadingInstance = ElLoading.service({ lock: true, text: '拼命加载中...', background: 'rgba(0, 0, 0, 0.7)' }) } needLoadingRequestCount++ } export const hideLoading = () => { if (needLoadingRequestCount <= 0) return needLoadingRequestCount-- if (needLoadingRequestCount === 0) { loadingInstance.close() } } ``` 2. **在组件中使用** ```vue <script setup> import { onMounted } from 'vue' import { showLoading, hideLoading } from '@/utils/loading' import { fetchData } from '@/api' onMounted(async () => { showLoading() try { await fetchData() } finally { hideLoading() } }) </script> ``` ### 二、优化方案(支持并发请求) ```javascript // 修改loading.js中的计数器逻辑 export const hideLoading = () => { needLoadingRequestCount = Math.max(0, needLoadingRequestCount - 1) if (needLoadingRequestCount === 0) { setTimeout(() => { // 防抖处理 loadingInstance?.close() }, 300) } } ``` ### 三、路由级全局控制 ```javascript // router.js import { showLoading, hideLoading } from '@/utils/loading' router.beforeEach(() => { showLoading() }) router.afterEach(() => { hideLoading() }) ``` ### 四、注意事项 1. 当使用`async/await`时,务必在`finally`中关闭loading 2. 需要处理网络错误时的loading关闭[^2] 3. 遮罩层级建议设置为`z-index: 2000`(与Element Plus默认保持一致) 4. 可搭配CSS动画提升体验: ```css .el-loading-spinner { animation: rotate 2s linear infinite; } @keyframes rotate { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值