MessageBox

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

简介

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

基于 Nuxt UI 的 Modal 组件封装

用法

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 模式按钮文案,confirmLabelcancelLabel 分别覆盖 confirm 模式的两个按钮:

<template>
  <MMessageBox
    mode="confirm"
    alert-confirm-label="我已知晓"
    confirm-label="我同意"
    cancel-label="我不同意"
  >
    <UButton variant="outline" label="文案覆盖" />
  </MMessageBox>
</template>

buttonProps 按钮属性

confirmButtoncancelButton 接收完整 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"

控制消息框的操作模式。 alert 仅显示确认按钮,confirm 显示取消与确认按钮。

alertConfirmLabel'知道了'string

alert 模式下的确认按钮文本。

confirmLabel'确认'string

确认按钮文本。

cancelLabel'取消'string

取消按钮文本。

descriptionstring
contentDialogContentProps & Partial<EmitsToProps<DialogContentImplEmits>>

The content of the modal.

portaltruestring | false | true | HTMLElement

Render the modal in a portal.

closetrueboolean | Omit<ButtonProps, LinkPropsKeys>

Display a close button to dismiss the modal. { size: 'md', color: 'neutral', variant: 'ghost' }

closeIconappConfig.ui.icons.closeany

The icon displayed in the close button.

icon'i-lucide-circle-question-mark'any

标题前展示的图标名称。

confirmButtonButtonProps

透传给确认按钮的属性。 未显式指定 color 时会默认继承当前 type

cancelButtonButtonProps

透传给取消按钮的属性。 仅在 mode='confirm' 时渲染。

openboolean
dismissiblefalseboolean

false 时,点击遮罩层或按下 Esc 键将不会关闭模态框。

overlaytrueboolean

Render an overlay behind the modal.

scrollablefalseboolean

When true, enables scrollable overlay mode where content scrolls within the overlay.

transitiontrueboolean

Animate the modal when opening or closing.

fullscreenfalseboolean

When true, the modal will take up the full screen.

modalboolean

The modality of the dialog When set to true,
interaction with outside elements will be disabled and only dialog content will be visible to screen readers.

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

app.config.ts
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'
          }
        }
      }
    }
  }
})

Changelog

No recent changes
Copyright © 2025 - 2026 YiXuan - MIT License