如何通过Vue的emit实现加载遮罩组件的显示与隐藏?
问题分析与修正方案
你的代码存在这几个核心问题:
- 事件传递方向搞反:
defineEmits是子组件用来向父组件发送事件的API,你在父组件里调用emit("showLoader"),本质是向父组件的上级组件发事件,根本传不到AppLoader子组件。 - loading状态逻辑错误:子组件的
showLoader是取反操作,但你需要的是直接通过true/false控制显示隐藏,不是切换状态。 - 异步逻辑处理缺失:你在
onMounted里同步调用"显示"和"隐藏",API请求是异步的,代码执行太快会导致loader根本来不及显示。 - 模板与样式重复控制:同时用
v-if和class控制显示,逻辑冗余。
修正后的代码
1. 重构AppLoader.vue(子组件)
子组件只负责接收父组件传递的loading状态,根据状态显示/隐藏加载层:
<script setup lang="ts"> import { defineProps } from 'vue'; // 定义props接收父组件的loading状态 const props = defineProps<{ loading: boolean; }>(); </script> <template> <!-- 用props直接控制加载层显示,简化逻辑 --> <div v-if="props.loading" class="loader f-height f-width"> LOADER WHOOOOOO </div> <slot></slot> </template> <style src="./app-loader.css" scoped lang="postcss" />
2. 简化app-loader.css
因为已经用v-if控制显示,去掉.loading类:
.loader { background: red; width: 100%; height: 100%; position: absolute; top: 0; left: 0; z-index: 10; opacity: 0.5; }
3. 修改使用组件的页面(父组件)
父组件维护loading状态,通过props传递给子组件,同时用异步逻辑处理API请求:
<template> <AppLoader :loading="isLoading"> Some stuff that takes a while to load.... </AppLoader> </template> <script lang="ts" setup> import { ref, onMounted } from 'vue'; import AppLoader from './AppLoader.vue'; const isLoading = ref(false); onMounted(async () => { isLoading.value = true; // 开始请求时显示loader try { // 替换成你的实际API请求 await fetch('https://your-api-url.com/data'); // 处理返回的数据 } catch (err) { // 处理请求错误 } finally { isLoading.value = false; // 请求结束后隐藏loader } }); </script>
逻辑说明
- 父组件负责维护loading状态和处理异步请求,子组件只做UI展示,符合组件职责单一原则。
- 用
async/await确保loader在请求全周期内正确显示,避免同步代码导致的闪屏问题。 - 父组件通过props传递状态是Vue中父控子的标准方式,emit则是子组件通知父组件(比如子组件内部触发的操作需要告知父组件),不要搞混两者的使用场景。
内容的提问来源于stack exchange,提问作者Some Name
相关产品推荐
相关产品推荐

