---
title: "MessageBox"
description: "模态消息对话框，提供声明式与编程式两种调用方式。"
seo_title: "MessageBox"
seo_description: "A modal message dialog component, offering both declarative and programmatic (alert/confirm) usage."
canonical_url: "https://nuxt.mhaibaraai.cn/docs/components/message-box"
---
# MessageBox

> 模态消息对话框，提供声明式与编程式两种调用方式。

## 简介

`MMessageBox` 是一个模态对话框组件，适用于重要通知或需要用户明确确认的场景。提供 `alert` 与 `confirm` 两种模式，内置六种语义化类型，并支持通过 `useMessageBox()` 进行编程式调用。

> \[\!NOTE\]
> See: https://ui.nuxt.com/docs/components/modal
> 
> 基于 Nuxt UI 的 Modal 组件封装

## 用法

`default` 插槽放置触发元素，组件内部由 `UModal` 自动管理打开状态：

```vue
<template>
  <MMessageBox title="提交保存" description="点击「知道了」关闭弹窗。">
    <UButton label="打开" />
  </MMessageBox>
</template>
```

### `mode` 模式

`alert` 仅显示确认按钮，`confirm` 同时提供取消与确认并返回布尔结果：

```vue
<template>
  <MMessageBox mode="confirm">
    <UButton label="打开" color="neutral" variant="subtle" />
  </MMessageBox>
</template>
```

### `type` 类型

`type` 影响默认图标与确认按钮颜色，包含六种语义化值：

```vue
<template>
  <MMessageBox type="primary" mode="confirm">
    <UButton label="打开" color="neutral" variant="subtle" />
  </MMessageBox>
</template>
```

### `icon` 图标

`icon` 覆盖 `type` 默认图标，传入任意 Iconify 图标名称：

```vue
<template>
  <MMessageBox icon="i-lucide-rocket">
    <UButton variant="soft" color="success" label="部署完成" />
  </MMessageBox>
</template>
```

### `label` 文案

`alertConfirmLabel` 控制 `alert` 模式按钮文案，`confirmLabel` 与 `cancelLabel` 分别覆盖 `confirm` 模式的两个按钮：

```vue
<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：

```vue
<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)` 标记为未确认：

```vue
<template>
  <MMessageBox dismissible>
    <UButton variant="outline" color="neutral" label="关闭策略" />
  </MMessageBox>
</template>
```

## 示例

### 受控状态

通过 `v-model:open` 外部控制开关，适合编程式触发与多按钮联动：

```vue [ComponentsMessageBoxControlledExample.vue]
<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` 可在正文内主动关闭弹窗：

```vue [ComponentsMessageBoxBodySlotExample.vue]
<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` 插槽完全接管标题区，覆盖默认的图标加文本组合：

```vue [ComponentsMessageBoxTitleSlotExample.vue]
<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 配合工作：

```vue [ComponentsMessageBoxDescriptionSlotExample.vue]
<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 容器，可自定义布局与排版：

```vue [ComponentsMessageBoxHeaderSlotExample.vue]
<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` 用于关闭弹窗：

```vue [ComponentsMessageBoxFooterSlotExample.vue]
<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 与样式：

```vue [ComponentsMessageBoxCloseSlotExample.vue]
<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 的整体布局，适合极致定制场景：

```vue [ComponentsMessageBoxContentSlotExample.vue]
<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>`：

```vue [ComponentsMessageBoxProgrammaticExample.vue]
<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

```ts
/**
 * Props for the MMessageBox component
 */
interface MMessageBoxProps {
  /**
   * 模态框标题文本。
   * @default "\"提示\""
   */
  title?: string | undefined;
  /**
   * 控制消息框的语义类型。
   * 会影响默认图标与确认按钮颜色。
   * @default "\"primary\""
   */
  type?: "error" | "primary" | "info" | "success" | "warning" | "neutral" | undefined;
  /**
   * 标题前展示的图标名称。
   */
  icon?: any;
  /**
   * 控制消息框的操作模式。
   * `alert` 仅显示确认按钮，`confirm` 显示取消与确认按钮。
   * @default "\"alert\""
   */
  mode?: "alert" | "confirm" | undefined;
  /**
   * 当 `false` 时，点击遮罩层或按下 `Esc` 键将不会关闭模态框。
   */
  dismissible?: boolean | undefined;
  /**
   * alert 模式下的确认按钮文本。
   * @default "\"知道了\""
   */
  alertConfirmLabel?: string | undefined;
  /**
   * 确认按钮文本。
   * @default "\"确认\""
   */
  confirmLabel?: string | undefined;
  /**
   * 取消按钮文本。
   * @default "\"取消\""
   */
  cancelLabel?: string | undefined;
  /**
   * 透传给确认按钮的属性。
   * 未显式指定 `color` 时会默认继承当前 `type`。
   */
  confirmButton?: ButtonProps | undefined;
  /**
   * 透传给取消按钮的属性。
   * 仅在 `mode='confirm'` 时渲染。
   */
  cancelButton?: ButtonProps | undefined;
  ui?: (Record<string, SlotClass> & { overlay?: SlotClass; content?: SlotClass; header?: SlotClass; wrapper?: SlotClass; body?: SlotClass; footer?: SlotClass; title?: SlotClass; description?: SlotClass; close?: SlotClass; icon?: SlotClass; }) | undefined;
  description?: string | undefined;
  /**
   * The content of the modal.
   */
  content?: (Omit<DialogContentProps, "as" | "asChild" | "forceMount"> & Partial<EmitsToProps<DialogContentImplEmits>>) | undefined;
  /**
   * Render an overlay behind the modal.
   */
  overlay?: boolean | undefined;
  /**
   * When `true`, enables scrollable overlay mode where content scrolls within the overlay.
   */
  scrollable?: boolean | undefined;
  /**
   * Animate the modal when opening or closing.
   */
  transition?: boolean | undefined;
  /**
   * When `true`, the modal will take up the full screen.
   */
  fullscreen?: boolean | undefined;
  /**
   * Render the modal in a portal.
   */
  portal?: string | boolean | HTMLElement | undefined;
  /**
   * Display a close button to dismiss the modal.
   * `{ size: 'md', color: 'neutral', variant: 'ghost' }`{lang="ts-type"}
   */
  close?: boolean | Omit<ButtonProps, LinkPropsKeys> | undefined;
  /**
   * The icon displayed in the close button.
   */
  closeIcon?: any;
  /**
   * The modality of the dialog When set to `true`, <br>
   * interaction with outside elements will be disabled and only dialog content will be visible to screen readers.
   */
  modal?: boolean | undefined;
  /**
   * When set to `false`, the dialog content will not be unmounted when closed, but instead hidden with CSS. <br>
   * Useful for SEO or when you want to improve performance by not remounting the component on every open.
   */
  unmountOnHide?: boolean | undefined;
  open?: boolean | undefined;
}
```

### Emits

```ts
/**
 * Emitted events for the MMessageBox component
 */
interface MMessageBoxEmits {
  close: (payload: [confirmed: boolean]) => void;
  update:open: (payload: [value: boolean | undefined]) => void;
}
```

### Slots

```ts
/**
 * Slots for the MMessageBox component
 */
interface MMessageBoxSlots {
  default(): any;
  content(): any;
  header(): any;
  title(): any;
  description(): any;
  actions(): any;
  close(): any;
  body(): any;
  footer(): any;
}
```

## Theme

<component-theme></component-theme>## Changelog

See commit history for [src/runtime/components/MessageBox.vue](https://github.com/mhaibaraai/movk-nuxt/commits/main/src/runtime/components/MessageBox.vue).


## Sitemap

See the full [sitemap](/sitemap.md) for all pages.
