一、为什么 B 端项目中弹窗会特别多?
B 端系统通常具备:
- 操作类型多:编辑、批量处理、配置等
- 流程复杂:强依赖弹窗进行中断式交互
- 表格行内操作密集:每一行可能都是入口
- 多业务复用同一弹窗
因此一个成熟 B 端项目往往会出现几十个弹窗。
二、普通实现方式的问题
1. 性能问题:大量组件提前加载或重复加载
- 主包体积膨胀
- 异步组件未缓存时每次打开都重新 import
2. 维护困难:共用弹窗逻辑散乱
弹窗内部写了大量 if / else 来区分业务场景。
3. 生命周期问题:使用 v-show 导致状态不重置
- 表单内容残留
- 校验状态残留
- 触发错乱
4. 组件内部请求导致重复请求
弹窗重新创建一次 → onMounted 再执行一次 → 请求重复。
三、优化思路(核心)
1. v-if 控制弹窗渲染
保证弹窗关闭后完全卸载,状态干净。
2. 异步组件缓存(避免重复加载)
只缓存组件定义,而不是组件实例。
3. 请求不写在弹窗内部
避免重复请求 & 业务耦合。
4. 请求写在外部,但只在“打开弹窗时触发”
避免未打开弹窗时浪费请求。
5. 弹窗组件只负责 UI,不负责业务逻辑(真正的单一职责)
四、弹窗体系结构图
graph TD
A[User Action] --> B{Need Dialog}
B -->|No| Z[Finish]
B -->|Yes| C[Prepare Data<br/>request cache mode]
C --> D[openDialog]
D --> E{Render v-if}
E --> F[Create Instance]
F --> G[Init UI props]
G --> H[Emit Events]
H --> I[Save or Refresh]
I --> J[Close Dialog]
J --> K[Destroy Instance]
五、核心代码示例
1. 弹窗注册表
export const DIALOG_REGISTRY = {
EditCampaign: () => import('../dialogs/EditCampaign.vue'),
SetBudget: () => import('../dialogs/SetBudget.vue'),
AddTag: () => import('../dialogs/AddTag.vue'),
};
2. 缓存异步组件
const cache = {};
export const useDialogLoader = (dialogMode) => {
return computed(() => {
const mode = dialogMode.value;
if (!cache[mode]) {
cache[mode] = defineAsyncComponent(DIALOG_REGISTRY[mode]);
}
return cache[mode];
});
};
3. 弹窗管理器
export function useDialog() {
const dialogVisible = ref(false);
const dialogMode = ref(null);
const dialogData = ref(null);
const dialogComponent = useDialogLoader(dialogMode);
function openDialog(mode, data) {
dialogMode.value = mode;
dialogData.value = data;
dialogVisible.value = true;
}
function closeDialog() {
dialogVisible.value = false;
}
return { dialogVisible, dialogComponent, dialogData, openDialog, closeDialog };
}
4. 外层控制数据请求(只在打开时触发)
async function onEditClick(id) {
const detail = await fetchDetail(id); // 不提前请求,不重复请求
openDialog("EditCampaign", { detail });
}
5. 弹窗内部(只负责 UI)
<script setup>
const props = defineProps({
detail: Object,
loading: Boolean
});
watch(() => props.detail, (detail) => {
if (detail) initForm(detail);
});
</script>
六、优化后效果
| 项目维度 | 优化前 | 优化后 |
|---|---|---|
| 首屏性能 | 所有弹窗提前加载 | 按需加载 + 组件缓存 |
| 弹窗打开速度 | 每次重复 import | 首次慢,后续秒开 |
| 请求逻辑 | 组件内重复请求 | 外层控制、无重复 |
| 状态管理 | 容易残留、错乱 | v-if 销毁后完全干净 |
| 可维护性 | 业务与 UI 混杂 | UI 纯展示,逻辑外移 |
| 弹窗复用性 | 差 | props 驱动,高复用度 |
七、总结
一个优秀的 B 端弹窗体系应该具备:
- 弹窗 v-if 控制实例创建与销毁
- 异步组件缓存,避免重复加载
- 请求逻辑和 UI 分离(真正单一职责)
- 请求只在“打开弹窗”时触发
- 弹窗通过 props 驱动,不依赖内部逻辑
- 可维护、可复用、性能优秀
通过以上优化,你的弹窗将更加:
- 更快
- 更稳定
- 更易维护
- 更易复用
并且能够非常轻松应对复杂 B 端业务。