emit("toolbarClick", name)
触发的事件可能会调用一个接口,在接口返回后再关闭 itemLoading
。由于 emit
触发的自定义事件返回值通常不会是 Promise
,实际异步操作应该在监听该事件的组件里处理。下面给出两种不同场景下的解决方案。
场景一:在当前组件处理异步操作
若异步操作在当前组件里处理,可将异步操作封装成 Promise
并返回,确保 toolbarResult
是 Promise
对象。
xml
PageContent.vue
Apply
<script setup>
// ... 已有代码 ...
// 操作栏
function handleToolbar(name) {
switch (name) {
// ... 已有代码 ...
default:
itemLoading[name] = true; // 开始加载
// 自定义事件处理函数返回 Promise
const toolbarResult = new Promise((resolve) => {
const result = emit("toolbarClick", name, resolve);
// 如果 emit 返回的本身就是 Promise,直接使用
if (isPromise(result)) {
result.then(resolve).catch(resolve);
}
});
if (isPromise(toolbarResult)) {
toolbarResult.finally(() => {
itemLoading[name] = false; // 结束加载
});
} else {
itemLoading[name] = false; // 非 Promise 直接结束加载
}
break;
}
}
// ... 已有代码 ...
</script>
场景二:在父组件处理异步操作
若异步操作在父组件处理,可在父组件监听 toolbarClick
事件时,通过传入的回调函数告知当前组件操作完成。
当前组件(PageContent.vue)
xml
PageContent.vue
Apply
<script setup>
// ... 已有代码 ...
// 操作栏
function handleToolbar(name) {
switch (name) {
// ... 已有代码 ...
default:
itemLoading[name] = true; // 开始加载
emit("toolbarClick", name, () => {
itemLoading[name] = false; // 结束加载
});
break;
}
}
// ... 已有代码 ...
</script>
父组件示例
xml
vue
Apply
<template>
<PageContent @toolbarClick="handleToolbarClick" />
</template>
<script setup>
import PageContent from './PageContent.vue';
// 处理 toolbarClick 事件
const handleToolbarClick = async (name, done) => {
try {
// 模拟异步接口调用
await new Promise((resolve) => setTimeout(resolve, 2000));
console.log(`接口调用完成: ${name}`);
} catch (error) {
console.error('接口调用出错:', error);
} finally {
// 调用 done 函数告知子组件操作完成
done();
}
};
</script>
总结如下:
- 场景一:把异步操作封装成
Promise
,确保toolbarResult
为Promise
对象,在finally
里关闭加载状态。 - 场景二:在父组件监听事件时,通过传入的回调函数告知子组件操作完成,从而关闭加载状态。
若异步操作在当前组件处理,推荐场景一;若在父组件处理,推荐场景二。