通用Modal应通过slots解耦内容(header/default/footer)、emit暴露confirm/cancel/close事件、props控制显隐与行为,实现高复用与强定制。

封装一个通用 Modal 弹窗,核心是解耦内容、行为与样式——用 slots 承载任意内容(标题、主体、底部按钮),用 emit 对外暴露交互事件(如确认、取消、关闭),再配合 props 控制显隐和基础配置。这样既能复用,又不牺牲灵活性。
用 slots 分离结构,支持高度定制
Modal 的内容千变万化:可能是表单、提示语、加载状态,甚至嵌套子组件。硬编码内容会严重限制复用性。推荐至少定义三个具名 slot:
- header:自定义标题区域(可含关闭按钮、图标等)
- default:主体内容(表单、文字、图片等,最常用)
- footer:操作按钮区域(确认/取消/自定义按钮)
在子组件中直接使用 <slot name="header"></slot> 即可,父组件按需传入。不需要某部分时,不传对应 slot 即可——Vue 会自动跳过渲染,无冗余 DOM。
用 emit 触发关键行为,保持调用方可控
Modal 不该自己决定“点了确定后做什么”,而应把动作权交还给父组件。通过 emit 抛出标准事件:
- confirm:用户点击确认按钮时触发(可携带表单数据或回调参数)
- cancel:点击取消或遮罩层时触发
- close:手动关闭(如点击右上角 × 或 ESC 键)
父组件监听这些事件即可执行业务逻辑:@confirm="handleSubmit"、@close="resetForm"。注意:避免在 Modal 内部直接调用 API 或跳转路由,那会破坏通用性。
用 props 控制状态与行为,兼顾简洁与扩展
基础 props 至少包括:
- v-model:visible(推荐)或 visible:双向绑定控制显隐(配合
defineModel或emit('update:visible')) - title(可选):当未使用 header slot 时的默认标题
- mask-closable:是否允许点击遮罩关闭(默认 true)
- esc-closable:是否允许按 ESC 关闭(默认 true)
- width / centered:布局微调,提升复用适应性
props 不宜过多,优先用 slot 替代静态配置项(比如“按钮文字”就交给 footer slot,而不是加 ok-text prop)。
实战小技巧:让关闭更健壮
关闭逻辑容易遗漏细节。建议统一处理三类关闭来源:
- 点击遮罩层 → 检查
mask-closable,再 emit 'close' 和 'cancel' - 按 ESC 键 → 在
onKeydown中拦截Escape,检查esc-closable - 点击右上角 × → 触发
emit('close'),不混用 cancel(语义更清晰)
同时,在父组件中,v-model:visible 更新后,建议加 v-if 控制 Modal 实例销毁(避免隐藏但 DOM 仍存在),提升性能和状态纯净度。

















