上午好☀️☀️☀️️
本答案参考通义千问
在使用 Vben Admin 的 useVbenModal 时,如果你遇到了嵌套 Modal 弹窗关闭行为异常的问题,即:点击第二层弹窗以外、第一层弹窗以内的区域时,两个弹窗同时关闭,这是由于默认的 Modal 配置中未正确区分“模态层级”所导致的。
✅ 问题原因分析
你目前使用的 useVbenModal 创建的是一个独立的 Modal 实例,但当你在第一层 Modal 内部再次调用 useVbenModal 创建第二层 Modal 时,第二个 Modal 并没有被正确地设置为第一个 Modal 的子级,因此它会默认具有“全局”层级,从而导致点击外部区域时触发了所有 Modal 的关闭。
✅ 解决方案(重点)
为了实现“只关闭当前弹窗,不影响其他弹窗”,你需要确保:
- 第二层 Modal 被设置为第一层 Modal 的子级。
- 禁止第二层 Modal 的外层点击关闭行为。
以下是详细的解决步骤和代码示例:
1. 修改第一层 Modal 的配置
确保第一层 Modal 允许内部嵌套 Modal,并且不阻止事件冒泡。
const [Modal, modalApi] = useVbenModal({
draggable: true,
fullscreenButton: false,
class: 'w-[1000px]',
onCancel() {
modalApi.close();
},
onConfirm: async () => {},
async onOpenChange(isOpen: boolean) {
if (isOpen) {
await initData();
}
},
title: $t('ui.widgets.setting'),
// 设置 modal 的 z-index 层级,防止被遮挡
zIndex: 1000,
});
2. 创建第二层 Modal 时,将其作为第一层 Modal 的子级
在第一层 Modal 内部,使用 modalApi 来打开第二层 Modal,并设置其为“子 Modal”。
// 在第一层 Modal 内部的方法中打开第二层 Modal
async function openSecondModal() {
const [SecondModal, secondModalApi] = useVbenModal({
title: '这是第二层弹窗',
content: '这是第二层弹窗内容',
width: 500,
// 禁止点击外部关闭
closeOnClickMask: false,
// 设置为第一层 Modal 的子级
parent: modalApi,
onOk: async () => {
secondModalApi.close();
},
onCancel: async () => {
secondModalApi.close();
},
});
SecondModal();
}
3. 在模板中添加按钮触发第二层 Modal
<template>
<Modal>
<div>这是第一层弹窗</div>
<button @click="openSecondModal">打开第二层弹窗</button>
</Modal>
</template>
✅ 总结
| 步骤 | 操作 |
|------|------|
| 1 | 使用 useVbenModal 创建第一层 Modal,设置合适的 zIndex。 |
| 2 | 在第一层 Modal 内部调用 useVbenModal 创建第二层 Modal,并通过 parent: modalApi 设置为子 Modal。 |
| 3 | 设置 closeOnClickMask: false,防止点击外部区域关闭第二层 Modal。 |
| 4 | 保证 onOk 和 onCancel 仅关闭当前 Modal。 |
✅ 修改后的完整代码示例
<script setup lang="ts">
import { useVbenModal } from '@vben/common-ui';
import { $t } from '#/locales';
const [Modal, modalApi] = useVbenModal({
draggable: true,
fullscreenButton: false,
class: 'w-[1000px]',
onCancel() {
modalApi.close();
},
onConfirm: async () => {},
async onOpenChange(isOpen: boolean) {
if (isOpen) {
await initData();
}
},
title: $t('ui.widgets.setting'),
zIndex: 1000,
});
async function initData() {}
async function openSecondModal() {
const [SecondModal, secondModalApi] = useVbenModal({
title: '这是第二层弹窗',
content: '这是第二层弹窗内容',
width: 500,
closeOnClickMask: false,
parent: modalApi,
onOk: async () => {
secondModalApi.close();
},
onCancel: async () => {
secondModalApi.close();
},
});
SecondModal();
}
</script>
<template>
<Modal>
<div>这是第一层弹窗</div>
<button @click="openSecondModal">打开第二层弹窗</button>
</Modal>
</template>
✅ 注意事项
- 如果你使用的是 Vue 3 + Composition API,请确保你使用的是最新的
@vben/common-ui 版本。 - 如果你仍然遇到层级问题,可以尝试手动设置
zIndex 或使用 CSS 控制 Modal 层级。
如需进一步优化 Modal 嵌套体验,也可以考虑使用 ModalStack 或 自定义 Modal 管理器 来管理多层 Modal 的显示与关闭逻辑。