子组件应在异步流程真正收尾(含数据处理、错误判断、UI准备就绪)后 emit('loading-change', false),父组件通过 Map 聚合多来源 loading 状态并用 computed 统一控制遮罩层等;成功 emit('ready'),失败 emit('error'),避免仅在 then 中关闭 loading 导致状态卡住。
子组件完成异步操作后,通过 emit 通知父组件结束 loading,关键在于“时机准确”和“状态同步”。不是等请求返回就立刻 emit,而是确保整个异步流程真正收尾——包括数据处理、错误判断、UI 更新准备就绪——再发出信号。
loading 状态的生命周期必须与真实异步行为严格对齐:
emit('loading-change', true),比如点击按钮或 onMounted 触发请求时.then() / .catch() 或 try/catch 的 finally 块中调用 emit('loading-change', false)
nextTick 后聚焦输入框),建议等这些也完成后 emit,避免父组件过早认为“已就绪”父组件不直接信任单个子组件的 loading,而是统一管理多个来源的状态:
ref({}) 或 reactive(new Map()) 记录每个子组件的 loading 值,例如 loadingMap.set('form-panel', true)
computed 判断全局是否仍在加载:const isLoading = computed(() => Array.from(loadingMap.values()).some(Boolean))
isLoading 绑定到遮罩层、按钮禁用或骨架屏上,实现视觉反馈一致性单纯 loading-change: false 只说明“不忙了”,但父组件可能还想知道“是成功了?出错了?还是数据还没准备好?”:
emit('ready'),父组件据此触发 scrollIntoView 或表单自动聚焦emit('error', { message, code }),由父组件统一展示提示或重试入口Promise.all 包裹它们各自的 ready 事件监听逻辑避免 loading 状态“假结束”或“卡住”:
mounted 里盲目发 loading-change: true,此时可能还没发起请求then 里发 false,漏掉 catch 就会导致 loading 一直挂着