Skip to content

MessageBox 消息弹框

模拟系统的消息提示框而实现的一套模态对话框组件。

名称分类说明类型默认值
type? 风格消息类型'success' | 'warning' | 'info' | 'danger' | 'error'
cancelButtonType? 风格取消按钮类型ButtonType
confirmButtonType? 风格确认按钮类型ButtonType'primary'
center? 风格是否居中布局booleanfalse
inputType? 风格输入框类型'text' | 'textarea' | 'password' | 'number''text'
customClass? 风格自定义对话框根元素的类名string
customStyle? 风格自定义对话框根元素的内联样式CSSProperties
width? 风格自定义对话框宽度(数字为 px,字符串为 CSS 值)string | number420
overlayClass? 风格自定义遮罩层的类名string | string[] | Record<string, boolean>
showClose? 行为是否显示关闭按钮booleantrue
showCancelButton? 行为是否显示取消按钮booleanfalse
showConfirmButton? 行为是否显示确认按钮booleantrue
lockScroll? 行为是否锁定滚动booleantrue
closeOnClickModal? 行为是否可通过点击遮罩关闭booleantrue
showInput? 行为是否显示输入框booleanfalse
callback? 行为关闭后的回调函数(action: MessageBoxAction | { value: string; action: MessageBoxAction }) => void
beforeClose? 行为关闭前的回调,调用 done 关闭弹框;若返回 Promise,按钮自动显示加载状态(action: MessageBoxAction, instance: MessageBoxOptions, done: () => void) => void | Promise<void>
closeOnPressEscape? 行为是否可通过按 Escape 键关闭booleantrue
closeOnHashChange? 行为是否在 URL hash 变化时关闭booleantrue
inputSchema? 行为输入框的 Zod 验证 schemaZodType
distinguishCancelAndClose? 行为关闭按钮是否触发 "close" 而非 "cancel"booleantrue
draggable? 行为是否可通过拖拽标题栏移动对话框booleanfalse
title? 内容标题string
message? 内容消息内容string | VNode
cancelButtonText? 内容取消按钮文字string'No'
confirmButtonText? 内容确认按钮文字string'Yes'
inputPlaceholder? 内容输入框占位文本string
inputValue? 内容输入框初始值string
inputErrorMessage? 内容验证失败时的自定义错误提示string
footer? 内容自定义底部内容,替换默认按钮VNode | (() => VNode)
PxMessageBox? 方法打开消息弹框(options: MessageBoxOptions) => Promise<MessageBoxData>
PxMessageBox.alert? 方法打开 alert 弹框(message, title, options?) => Promise<MessageBoxData>
PxMessageBox.confirm? 方法打开 confirm 弹框(message, title, options?) => Promise<MessageBoxData>
PxMessageBox.prompt? 方法打开 prompt 弹框(message, title, options?) => Promise<MessageBoxData>
PxMessageBox.close? 方法关闭当前弹框() => void

Alert 消息提示

用于提示用户的消息,只有确认按钮。

<template>
  <px-button @click="showAlert">Show Alert</px-button>
</template>

<script setup lang="ts">
import { PxMessageBox } from 'sakana-element';

const showAlert = () => {
  PxMessageBox.alert('This is an alert message', 'Alert').catch(() => {});
};
</script>

Confirm 确认消息

用于提示用户确认操作,有确认和取消按钮。

<template>
  <px-button @click="showConfirm">Show Confirm</px-button>
</template>

<script setup lang="ts">
import { PxMessage, PxMessageBox } from 'sakana-element';

const showConfirm = async () => {
  try {
    await PxMessageBox.confirm('Are you sure to delete this item?', 'Confirm');
    PxMessage.success('Deleted successfully');
  } catch {
    PxMessage.info('Cancelled');
  }
};
</script>

Prompt 提交内容

用于提示用户输入内容。

<template>
  <px-button @click="showPrompt">Show Prompt</px-button>
</template>

<script setup lang="ts">
import { PxMessage, PxMessageBox } from 'sakana-element';

const showPrompt = async () => {
  try {
    const { value } = await PxMessageBox.prompt('Please input your name', 'Prompt');
    PxMessage.success(`Your name is: ${value}`);
  } catch {
    PxMessage.info('Cancelled');
  }
};
</script>

自定义内容

可以自定义消息框的内容。

<template>
  <px-button @click="showCustom">Custom MessageBox</px-button>
</template>

<script setup lang="ts">
import { PxMessage, PxMessageBox } from 'sakana-element';

const showCustom = async () => {
  try {
    await PxMessageBox({
      title: 'Warning',
      message: 'This action will permanently delete the file. Continue?',
      type: 'warning',
      showCancelButton: true,
      confirmButtonText: 'Yes, delete it',
      cancelButtonText: 'No, cancel',
    });
    PxMessage.success('Deleted!');
  } catch {
    PxMessage.info('Cancelled');
  }
};
</script>

居中布局

使用 center 属性使标题和底部按钮居中对齐。

<template>
  <px-button @click="showCenter">Center Layout</px-button>
</template>

<script setup lang="ts">
import { PxMessageBox } from 'sakana-element';

const showCenter = () => {
  PxMessageBox({
    title: 'Warning',
    message: 'This will center the title and footer.',
    type: 'warning',
    center: true,
    showCancelButton: true,
  }).catch(() => {});
};
</script>

关闭前回调

使用 beforeClose 拦截关闭操作。回调接收 actioninstancedone 函数 — 调用 done() 才会真正关闭对话框。如果 beforeClose 返回一个 Promise,被点击的按钮会自动显示加载状态,直到 Promise 完成。

<template>
  <div style="display: flex; gap: 8px; flex-wrap: wrap">
    <px-button @click="showCallbackStyle">Callback Style</px-button>
    <px-button @click="showAsyncStyle">Async / Promise Style</px-button>
  </div>
</template>

<script setup lang="ts">
import { PxMessage, PxMessageBox } from 'sakana-element';

const showCallbackStyle = () => {
  PxMessageBox({
    title: 'Confirm',
    message: 'Are you sure? The dialog will close after 1 second.',
    showCancelButton: true,
    beforeClose: (action, _instance, done) => {
      if (action === 'confirm') {
        setTimeout(() => {
          done();
          PxMessage.success('Confirmed after delay');
        }, 1000);
      } else {
        done();
      }
    },
  });
};

const showAsyncStyle = () => {
  PxMessageBox({
    title: 'Async Confirm',
    message: 'The confirm button will show a loading spinner for 1.5 seconds.',
    showCancelButton: true,
    beforeClose: (action, _instance, done) => {
      if (action === 'confirm') {
        return new Promise<void>((resolve) => {
          setTimeout(() => {
            done();
            PxMessage.success('Async operation completed');
            resolve();
          }, 1500);
        });
      }
      done();
    },
  });
};
</script>

类型彩色边框

type 设置为 'info''success''warning''danger',边框、阴影和分割线会显示对应的主题颜色。

<template>
  <div style="display: flex; gap: 8px; flex-wrap: wrap">
    <px-button type="info" @click="showType('info')">Info</px-button>
    <px-button type="success" @click="showType('success')">Success</px-button>
    <px-button type="warning" @click="showType('warning')">Warning</px-button>
    <px-button type="danger" @click="showType('danger')">Danger</px-button>
  </div>
</template>

<script setup lang="ts">
import { PxMessageBox } from 'sakana-element';

const showType = (type: 'info' | 'success' | 'warning' | 'danger') => {
  PxMessageBox({
    title: `${type.charAt(0).toUpperCase() + type.slice(1)} Type`,
    message: `This message box uses the "${type}" type, which colors the border, shadow, and divider.`,
    type,
    showCancelButton: true,
  }).catch(() => {});
};
</script>

自定义外观

使用 customClasscustomStylewidth 自定义对话框外观。width 接受数字(像素)或 CSS 字符串值。

<template>
  <div style="display: flex; gap: 8px; flex-wrap: wrap">
    <px-button @click="showCustomClass">Custom Class</px-button>
    <px-button @click="showCustomStyle">Custom Style</px-button>
    <px-button @click="showWidth">Custom Width</px-button>
  </div>
</template>

<script setup lang="ts">
import { PxMessageBox } from 'sakana-element';

const showCustomClass = () => {
  PxMessageBox.alert('This dialog has a custom CSS class applied.', 'Custom Class', {
    customClass: 'my-custom-msgbox',
  }).catch(() => {});
};

const showCustomStyle = () => {
  PxMessageBox.alert('This dialog has custom inline styles.', 'Custom Style', {
    customStyle: {
      '--px-message-box-bg': '#f0f9eb',
      '--px-message-box-border-color': '#67c23a',
    } as any,
  }).catch(() => {});
};

const showWidth = () => {
  PxMessageBox.alert('This dialog is 600px wide.', 'Custom Width (number)', { width: 600 }).catch(
    () => {},
  );
};
</script>

<style>
.my-custom-msgbox {
  --px-message-box-bg: #fdf6ec;
  --px-message-box-border-color: #e6a23c;
}
</style>

关闭控制

使用 closeOnPressEscapecloseOnHashChange 控制对话框的关闭方式,两者默认均为 true

<template>
  <div style="display: flex; gap: 8px; flex-wrap: wrap">
    <px-button @click="showNoEscape">Disable ESC Close</px-button>
    <px-button @click="showNoHashChange">Disable Hash Close</px-button>
  </div>
</template>

<script setup lang="ts">
import { PxMessageBox } from 'sakana-element';

const showNoEscape = () => {
  PxMessageBox({
    title: 'No ESC Close',
    message: 'Pressing Escape will NOT close this dialog. Use the buttons instead.',
    showCancelButton: true,
    closeOnPressEscape: false,
  }).catch(() => {});
};

const showNoHashChange = () => {
  PxMessageBox({
    title: 'No Hash Close',
    message: 'Changing the URL hash will NOT close this dialog.',
    showCancelButton: true,
    closeOnHashChange: false,
  }).catch(() => {});
};
</script>

输入验证

使用 inputSchema 配合 Zod schema 在确认前验证 prompt 输入。设置 inputErrorMessage 可自定义验证失败时输入框下方显示的错误文本。

<template>
  <px-button @click="showValidation">Email Validation</px-button>
</template>

<script setup lang="ts">
import { PxMessage, PxMessageBox } from 'sakana-element';
import { z } from 'zod';

const showValidation = async () => {
  try {
    const { value } = await PxMessageBox.prompt(
      'Please enter your email address',
      'Email Validation',
      {
        inputPlaceholder: 'user@example.com',
        inputSchema: z.string().email(),
        inputErrorMessage: 'Please enter a valid email address',
      },
    );
    PxMessage.success(`Email submitted: ${value}`);
  } catch {
    PxMessage.info('Cancelled');
  }
};
</script>

区分取消与关闭

distinguishCancelAndClosetrue(默认)时,点击关闭按钮会以 'close' 拒绝,而点击取消按钮会以 'cancel' 拒绝。设置为 false 时两者均触发 'cancel'

<template>
  <div style="display: flex; gap: 8px; flex-wrap: wrap">
    <px-button @click="show(true)">Distinguish (default)</px-button>
    <px-button @click="show(false)">Not Distinguished</px-button>
  </div>
</template>

<script setup lang="ts">
import { PxMessage, PxMessageBox } from 'sakana-element';

const show = async (distinguish: boolean) => {
  try {
    await PxMessageBox({
      title: distinguish ? 'Distinguish Close' : 'Not Distinguished',
      message: distinguish
        ? 'Close button fires "close", cancel button fires "cancel".'
        : 'Both close button and cancel button fire "cancel".',
      showCancelButton: true,
      distinguishCancelAndClose: distinguish,
    });
    PxMessage.success('Action: confirm');
  } catch (action) {
    PxMessage.info(`Action: ${action}`);
  }
};
</script>

可拖拽

draggable 设置为 true,用户可以通过拖拽标题栏移动对话框。对话框会被约束在视口范围内。

<template>
  <px-button @click="showDraggable">Draggable MessageBox</px-button>
</template>

<script setup lang="ts">
import { PxMessageBox } from 'sakana-element';

const showDraggable = () => {
  PxMessageBox({
    title: 'Draggable',
    message: 'Drag the header to move this dialog around.',
    showCancelButton: true,
    draggable: true,
  }).catch(() => {});
};
</script>

自定义底部

使用 footer 选项提供一个 VNode 或渲染函数,替换默认的取消/确认按钮为自定义内容。

<template>
  <px-button @click="showCustomFooter">Custom Footer</px-button>
</template>

<script setup lang="ts">
import { PxMessageBox } from 'sakana-element';
import { h } from 'vue';

const showCustomFooter = () => {
  PxMessageBox({
    title: 'Custom Footer',
    message: 'This dialog replaces the default buttons with a custom footer.',
    footer: () =>
      h('div', { style: 'text-align: center; padding: 8px 0' }, [
        h(
          'a',
          {
            href: '#',
            style: 'color: var(--px-color-primary); cursor: pointer',
            onClick: (e: Event) => {
              e.preventDefault();
              PxMessageBox.close();
            },
          },
          'I have read and agree to the terms',
        ),
      ]),
  }).catch(() => {});
};
</script>