MessageBox
简介
MMessageBox 是一个模态对话框组件,适用于重要通知或需要用户明确确认的场景。提供 alert 与 confirm 两种模式,内置六种语义化类型,并支持通过 useMessageBox() 进行编程式调用。
用法
default 插槽放置触发元素,组件内部由 UModal 自动管理打开状态:
<template>
<MMessageBox title="提交保存" description="点击「知道了」关闭弹窗。">
<UButton label="打开" />
</MMessageBox>
</template>
mode 模式
alert 仅显示确认按钮,confirm 同时提供取消与确认并返回布尔结果:
<template>
<MMessageBox mode="confirm">
<UButton label="打开" color="neutral" variant="subtle" />
</MMessageBox>
</template>
type 类型
type 影响默认图标与确认按钮颜色,包含六种语义化值:
<template>
<MMessageBox type="primary" mode="confirm">
<UButton label="打开" color="neutral" variant="subtle" />
</MMessageBox>
</template>
icon 图标
icon 覆盖 type 默认图标,传入任意 Iconify 图标名称:
<template>
<MMessageBox icon="i-lucide-rocket">
<UButton variant="soft" color="success" label="部署完成" />
</MMessageBox>
</template>
label 文案
alertConfirmLabel 控制 alert 模式按钮文案,confirmLabel 与 cancelLabel 分别覆盖 confirm 模式的两个按钮:
<template>
<MMessageBox
mode="confirm"
alert-confirm-label="我已知晓"
confirm-label="我同意"
cancel-label="我不同意"
>
<UButton variant="outline" label="文案覆盖" />
</MMessageBox>
</template>
buttonProps 按钮属性
confirmButton 与 cancelButton 接收完整 ButtonProps,可定制 icon、color、variant 与 label:
<template>
<MMessageBox
:confirm-button="{ label: '继续', icon: 'i-lucide-arrow-right', color: 'info' }"
:cancel-button="{ label: '取消', variant: 'ghost' }"
>
<UButton variant="outline" label="按钮属性" />
</MMessageBox>
</template>
dismissible 关闭策略
dismissible 默认为 false 严格模式;开启后允许点击遮罩或按 Esc 关闭,并通过 close(false) 标记为未确认:
<template>
<MMessageBox dismissible>
<UButton variant="outline" color="neutral" label="关闭策略" />
</MMessageBox>
</template>
示例
受控状态
通过 v-model:open 外部控制开关,适合编程式触发与多按钮联动:
<script setup lang="ts">
const open = ref(false)
const result = ref('')
</script>
<template>
<div class="flex gap-2">
<UButton variant="soft" @click="open = true">
外部按钮打开
</UButton>
<UButton color="neutral" variant="outline" @click="open = false">
外部按钮关闭
</UButton>
<span v-if="result" class="self-center text-sm text-muted">{{ result }}</span>
<MMessageBox
v-model:open="open"
mode="confirm"
type="primary"
title="确认执行同步"
:dismissible="false"
:modal="false"
description="open 由父组件持有,可被任意按钮、定时器或异步任务触发。"
@close="(ok: boolean) => result = `受控 → ${ok}`"
/>
</div>
</template>
正文插槽
body 插槽渲染富文本正文,slot 参数 close 可在正文内主动关闭弹窗:
<template>
<MMessageBox
mode="confirm"
type="primary"
title="服务条款更新"
>
<UButton color="primary" variant="soft" icon="i-lucide-file-text" label="阅读条款" />
<template #body="{ close }">
<p class="text-sm text-muted">
我们对服务条款进行了以下更新,请仔细阅读:
</p>
<ul class="mt-2 space-y-1 text-sm list-disc list-inside text-muted">
<li>数据收集范围已缩减</li>
<li>用户隐私保护条款已加强</li>
<li>退款政策已更新</li>
</ul>
<UButton
class="mt-3"
size="xs"
variant="ghost"
color="neutral"
label="先取消,稍后阅读"
@click="close"
/>
</template>
</MMessageBox>
</template>
标题插槽
title 插槽完全接管标题区,覆盖默认的图标加文本组合:
<template>
<MMessageBox
mode="confirm"
type="primary"
title="原标题文案"
description="标题区由 #title 插槽决定,原 title prop 不会渲染。"
>
<UButton variant="outline" label="自定义标题" />
<template #title>
<UIcon name="i-lucide-sparkles" class="size-5 text-primary" />
<span class="font-bold text-primary">完全自定义的标题样式</span>
<UBadge color="primary" variant="subtle" label="NEW" />
</template>
</MMessageBox>
</template>
描述插槽
description 插槽支持富文本描述,可与 title prop 配合工作:
<template>
<MMessageBox
mode="alert"
type="info"
title="版本更新说明"
>
<UButton variant="outline" label="查看说明" />
<template #description>
<span class="text-sm">
v2.0 已发布,详见
<a href="#" class="text-primary underline">完整变更日志</a>
,或继续使用旧版。
</span>
</template>
</MMessageBox>
</template>
头部插槽
header 插槽完整接管 title 与 description 容器,可自定义布局与排版:
<template>
<MMessageBox
mode="confirm"
type="warning"
title="原标题"
description="原描述"
>
<UButton variant="outline" label="自定义头部" />
<template #header>
<div class="flex items-center gap-3 p-4 bg-warning/10 rounded-t-lg">
<UIcon name="i-lucide-triangle-alert" class="size-8 text-warning" />
<div>
<div class="font-semibold">
高风险操作
</div>
<div class="text-xs text-muted">
头部插槽自定义整块布局
</div>
</div>
</div>
</template>
</MMessageBox>
</template>
操作插槽
footer 插槽完全接管按钮区,slot 参数 close 用于关闭弹窗:
<template>
<MMessageBox
mode="confirm"
type="primary"
title="步进式确认"
description="footer 插槽接管按钮区,可自由组合多按钮、分组、状态等。"
>
<UButton variant="outline" label="自定义操作" />
<template #footer="{ close }">
<UButton color="neutral" variant="ghost" label="稍后处理" @click="close" />
<UButton color="warning" variant="soft" label="保留并继续" @click="close" />
<UButton color="primary" label="立即应用" @click="close" />
</template>
</MMessageBox>
</template>
关闭按钮插槽
close 插槽自定义右上角关闭按钮,可改 icon、color 与样式:
<template>
<MMessageBox
mode="alert"
type="info"
title="自定义关闭按钮"
description="close 插槽完全替换默认关闭按钮。"
>
<UButton variant="outline" label="查看" />
<template #close>
<UButton size="xs" color="error" variant="ghost" icon="i-lucide-x-circle" />
</template>
</MMessageBox>
</template>
内容插槽
content 插槽替代 header / body / footer 的整体布局,适合极致定制场景:
<template>
<MMessageBox title="原标题">
<UButton variant="soft" color="primary" label="极致定制" />
<template #content="{ close }">
<div class="p-6 flex flex-col items-center gap-4 text-center">
<UIcon name="i-lucide-party-popper" class="size-12 text-primary" />
<div class="text-lg font-semibold">
恭喜达成成就
</div>
<p class="text-sm text-muted">
content 插槽替代 header/body/footer 三段式,可完全自定义内部结构。
</p>
<UButton label="收下奖励" @click="close" />
</div>
</template>
</MMessageBox>
</template>
命令式调用
使用 useMessageBox() 在任意逻辑中调用对话框,无需在模板中声明组件。alert() 返回 Promise<void>,confirm() 返回 Promise<boolean>:
<script setup lang="ts">
const { alert, confirm } = useMessageBox()
const alertResult = ref('')
const confirmResult = ref('')
async function showAlert() {
await alert({
type: 'success',
title: '操作成功',
description: '数据已成功提交,await 会等待弹窗关闭后继续执行。'
})
alertResult.value = 'await 后的逻辑已执行'
}
async function showConfirm() {
const ok = await confirm({
type: 'error',
title: '清空数据',
description: '即将清空所有本地缓存,此操作不可撤销。',
icon: 'i-lucide-database-zap',
confirmButton: { color: 'error', label: '确认清空' },
cancelButton: { label: '我再想想' }
})
confirmResult.value = ok ? '数据已清空' : '操作已取消'
}
</script>
<template>
<div class="space-y-3">
<div class="flex flex-wrap gap-3">
<div class="flex items-center gap-3">
<UButton
color="success"
variant="soft"
label="alert()"
icon="i-lucide-bell"
@click="showAlert"
/>
<span v-if="alertResult" class="text-sm text-muted">{{ alertResult }}</span>
</div>
<div class="flex items-center gap-3">
<UButton
color="error"
variant="outline"
label="confirm()"
icon="i-lucide-database-zap"
@click="showConfirm"
/>
<span v-if="confirmResult" class="text-sm text-muted">{{ confirmResult }}</span>
</div>
</div>
</div>
</template>
API
Props
| Prop | Default | Type |
|---|---|---|
title | '提示' | string模态框标题文本。 |
type | 'primary' | "primary" | "info" | "success" | "warning" | "error" | "neutral"控制消息框的语义类型。 会影响默认图标与确认按钮颜色。 |
mode | 'alert' | "alert" | "confirm"控制消息框的操作模式。
|
alertConfirmLabel | '知道了' | stringalert 模式下的确认按钮文本。 |
confirmLabel | '确认' | string确认按钮文本。 |
cancelLabel | '取消' | string取消按钮文本。 |
description | string | |
content | DialogContentProps & Partial<EmitsToProps<DialogContentImplEmits>>The content of the modal. | |
portal | true | string | false | true | HTMLElementRender the modal in a portal. |
close | true | boolean | Omit<ButtonProps, LinkPropsKeys>Display a close button to dismiss the modal.
|
closeIcon | appConfig.ui.icons.close | anyThe icon displayed in the close button. |
icon | 'i-lucide-circle-question-mark' | any标题前展示的图标名称。 |
confirmButton | ButtonProps透传给确认按钮的属性。
未显式指定 | |
cancelButton | ButtonProps透传给取消按钮的属性。
仅在 | |
open | boolean | |
dismissible | false | boolean当 |
overlay | true | booleanRender an overlay behind the modal. |
scrollable | false | booleanWhen |
transition | true | booleanAnimate the modal when opening or closing. |
fullscreen | false | booleanWhen |
modal | booleanThe modality of the dialog When set to | |
ui | { overlay?: ClassNameValue; content?: ClassNameValue; header?: ClassNameValue; wrapper?: ClassNameValue; body?: ClassNameValue; footer?: ClassNameValue; title?: ClassNameValue; description?: ClassNameValue; close?: ClassNameValue; icon?: ClassNameValue; } |
Emits
| Event | Type |
|---|---|
close | [confirmed: boolean] |
update:open | [value: boolean] |
Slots
| Slot | Type |
|---|---|
default | { open: boolean; } |
content | { close: () => void; } |
header | { close: () => void; } |
title | {} |
description | {} |
actions | {} |
close | { ui: { overlay: (props?: Record<string, any>) => string; content: (props?: Record<string, any>) => string; header: (props?: Record<string, any>) => string; wrapper: (props?: Record<string, any>) => string; body: (props?: Record<string, any>) => string; footer: (props?: Record<string, any>) => string; title: (props?: Record<string, any>) => string; description: (props?: Record<string, any>) => string; close: (props?: Record<string, any>) => string; }; } |
body | { close: () => void; } |
footer | { close: () => void; } |
Theme
export default defineAppConfig({
ui: {
messageBox: {
slots: {
title: 'flex gap-2 items-center',
footer: 'justify-end',
icon: 'size-5 shrink-0'
},
variants: {
type: {
primary: {
icon: 'text-primary'
},
info: {
icon: 'text-info'
},
success: {
icon: 'text-success'
},
warning: {
icon: 'text-warning'
},
error: {
icon: 'text-error'
},
neutral: {
icon: 'text-muted'
}
}
}
}
}
})