Dialog 对话框
新粗野主义风格的模态对话框,基于 reka-ui 的 Dialog 原语构建。支持遮罩层、关闭按钮和可组合的子组件。
预览
安装
pnpm dlx brutx-vue@latest add dialog用法
<script setup>
import { DialogRoot as Dialog, DialogTrigger, DialogClose } from 'reka-ui'
import { DialogContent, DialogHeader, DialogFooter, DialogTitle, DialogDescription } from 'brutx-ui-vue'
import { Button } from 'brutx-ui-vue'
</script>
<template>
<Dialog>
<DialogTrigger as-child>
<Button variant="primary">Open Dialog</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Edit Profile</DialogTitle>
<DialogDescription>
Make changes to your profile here. Click save when you're done.
</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose as-child>
<Button variant="outline">Cancel</Button>
</DialogClose>
<Button variant="primary">Save</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</template>尺寸
通过 DialogContent 的 size 属性控制对话框的最大宽度。默认值为 default(max-w-lg)。
| 尺寸 | 最大宽度 | 适用场景 |
|---|---|---|
sm | max-w-sm | 确认框、简单提示 |
default | max-w-lg | 标准表单、常规内容 |
lg | max-w-2xl | 多列表单、详细设置 |
xl | max-w-4xl | 复杂内容、数据展示 |
full | max-w-[calc(100vw-2rem)] | 大幅内容、全屏式交互 |
<script setup>
import { DialogRoot as Dialog, DialogTrigger } from 'reka-ui'
import { DialogContent, DialogHeader, DialogTitle, DialogDescription } from 'brutx-ui-vue'
import { Button } from 'brutx-ui-vue'
</script>
<template>
<Dialog>
<DialogTrigger as-child>
<Button variant="primary">打开小型对话框</Button>
</DialogTrigger>
<DialogContent size="sm">
<DialogHeader>
<DialogTitle>确认删除</DialogTitle>
<DialogDescription>此操作不可撤销,确定要继续吗?</DialogDescription>
</DialogHeader>
</DialogContent>
</Dialog>
</template>子组件
| 组件 | 说明 |
|---|---|
Dialog | 根组件(需从 reka-ui 导入:import { DialogRoot as Dialog } from 'reka-ui') |
DialogTrigger | 打开对话框的按钮(需从 reka-ui 导入:import { DialogTrigger } from 'reka-ui') |
DialogContent | 带遮罩层的对话框内容面板 |
DialogHeader | 头部容器 |
DialogFooter | 底部容器,弹性布局 |
DialogTitle | 对话框标题 |
DialogDescription | 对话框描述文本 |
DialogClose | 关闭按钮(需从 reka-ui 导入:import { DialogClose } from 'reka-ui') |
DialogOverlay | 背景遮罩层 |
DialogPortal | 传送门容器(需从 reka-ui 导入:import { DialogPortal } from 'reka-ui') |
DialogEnhanced | 支持可拖拽和可调整大小的增强版对话框 |
DialogEnhanced 用法
支持可拖拽和可调整大小的增强版对话框:
<script setup>
import { DialogRoot as Dialog, DialogTrigger } from 'reka-ui'
import { DialogEnhanced, DialogHeader, DialogTitle } from 'brutx-ui-vue'
</script>
<template>
<Dialog>
<DialogTrigger>打开可拖拽对话框</DialogTrigger>
<DialogEnhanced
draggable
resizable
:min-width="300"
:min-height="200"
drag-handle=".dialog-header"
>
<DialogHeader class="dialog-header">
<DialogTitle>可拖拽对话框</DialogTitle>
</DialogHeader>
<p>拖拽标题栏移动,拖拽边缘调整大小</p>
</DialogEnhanced>
</Dialog>
</template>API 参考
DialogContent
| 名称 | 类型 | 默认值 | 说明 |
|---|---|---|---|
showCloseButton | boolean | undefined | true | 控制内容面板右上角的内置关闭按钮是否渲染。 |
详情声明类型boolean | undefined 字面量
默认值详情
来源packages/ui/src/components/dialog/DialogContent.vue | |||
size | "default" | "full" | "lg" | "sm" | "xl" | undefined | "default" | 设置对话框内容面板的宽度变体。 |
详情声明类型NonNullable<"default" | "lg" | "sm" | "xl" | "full" | null | undefined> | undefined 字面量
默认值详情
来源packages/ui/src/components/dialog/DialogContent.vue | |||
entrance | "fade-zoom" | "shutter" | undefined | "fade-zoom" | 选择内容面板的入场动效变体。 |
详情声明类型NonNullable<"fade-zoom" | "shutter" | null | undefined> | undefined 字面量
默认值详情
来源packages/ui/src/components/dialog/DialogContent.vue | |||
forceMount | boolean | undefined | undefined | 将挂载保持策略传递给遮罩层和内容原语,以便在关闭状态下仍保持挂载。 |
详情声明类型boolean | undefined 字面量
默认值详情
来源packages/ui/src/components/dialog/DialogContent.vue | |||
class | string | undefined | undefined | 追加到对话框内容面板的自定义 CSS 类。 |
详情声明类型string | undefined 默认值详情
来源packages/ui/src/components/dialog/DialogContent.vue | |||
| 名称 | 签名或类型 | 说明 |
|---|---|---|
#default | {} | 渲染对话框的主体内容;内置关闭按钮会放在插槽内容之后。 |
详情声明类型{}来源packages/ui/src/components/dialog/DialogContent.vue | ||
DialogDescription
| 名称 | 类型 | 默认值 | 说明 |
|---|---|---|---|
class | string | undefined | — | 追加到描述元素的自定义 CSS 类;其余属性(例如 id)通过属性透传交给 Reka UI 原语。 |
详情声明类型string | undefined 默认值详情
来源packages/ui/src/components/dialog/DialogDescription.vue | |||
| 名称 | 签名或类型 | 说明 |
|---|---|---|
#default | {} | 对话框的辅助说明内容。 |
详情声明类型{}来源packages/ui/src/components/dialog/DialogDescription.vue | ||
DialogEnhanced
| 名称 | 类型 | 默认值 | 说明 |
|---|---|---|---|
draggable | boolean | undefined | false | 启用内容面板的指针拖拽移动;全屏模式下不应用拖拽移动样式。 |
详情声明类型boolean | undefined 字面量
默认值详情
来源packages/ui/src/components/dialog/DialogEnhanced.vue | |||
dragHandle | string | HTMLElement | undefined | undefined | 将拖拽起点限制为 CSS 选择器匹配的后代元素或指定 HTMLElement。 |
详情声明类型string | HTMLElement | undefined 默认值详情
来源packages/ui/src/components/dialog/DialogEnhanced.vue | |||
bounds | "viewport" | "parent" | { top: number; left: number; right: number; bottom: number; } | undefined | "viewport" | 限制拖拽位置到父容器、视口,或给定的 top、left、right、bottom 边界。 |
详情声明类型"viewport" | "parent" | { top: number; left: number; right: number; bottom: number; } | undefined字面量
默认值详情
来源packages/ui/src/components/dialog/DialogEnhanced.vue | |||
initialPosition | { x: number; y: number; } | undefined | undefined | 为几何状态控制器提供初始 x、y 坐标。 |
详情声明类型{ x: number; y: number; } | undefined默认值详情
来源packages/ui/src/components/dialog/DialogEnhanced.vue | |||
resizable | boolean | undefined | false | 启用对话框边缘的指针缩放交互。 |
详情声明类型boolean | undefined 字面量
默认值详情
来源packages/ui/src/components/dialog/DialogEnhanced.vue | |||
minWidth | number | undefined | 200 | 设置缩放时允许的最小宽度,单位为像素。 |
详情声明类型number | undefined 默认值详情
来源packages/ui/src/components/dialog/DialogEnhanced.vue | |||
minHeight | number | undefined | 150 | 设置缩放时允许的最小高度,单位为像素。 |
详情声明类型number | undefined 默认值详情
来源packages/ui/src/components/dialog/DialogEnhanced.vue | |||
maxWidth | number | undefined | undefined | 设置缩放时可选的最大宽度,单位为像素。 |
详情声明类型number | undefined 默认值详情
来源packages/ui/src/components/dialog/DialogEnhanced.vue | |||
maxHeight | number | undefined | undefined | 设置缩放时可选的最大高度,单位为像素。 |
详情声明类型number | undefined 默认值详情
来源packages/ui/src/components/dialog/DialogEnhanced.vue | |||
aspectRatio | number | undefined | undefined | 提供锁定的宽高比,由几何状态控制器用于调整尺寸。 |
详情声明类型number | undefined 默认值详情
来源packages/ui/src/components/dialog/DialogEnhanced.vue | |||
showCloseButton | boolean | undefined | true | 控制增强对话框内容面板中的内置关闭按钮是否渲染。 |
详情声明类型boolean | undefined 字面量
默认值详情
来源packages/ui/src/components/dialog/DialogEnhanced.vue | |||
forceMount | boolean | undefined | undefined | 要求遮罩层及内容在关闭状态仍保持挂载;此策略优先于 destroyOnClose。 |
详情声明类型boolean | undefined 字面量
默认值详情
来源packages/ui/src/components/dialog/DialogEnhanced.vue | |||
fullscreen | boolean | undefined | false | 将内容面板固定为占满视口的全屏布局,并忽略拖动几何样式。 |
详情声明类型boolean | undefined 字面量
默认值详情
来源packages/ui/src/components/dialog/DialogEnhanced.vue | |||
beforeClose | (() => boolean | Promise<boolean>) | undefined | undefined | 关闭请求前执行的同步或异步校验;返回 false 或抛出/reject 时不会发出关闭事件。 |
详情声明类型(() => boolean | Promise<boolean>) | undefined 默认值详情
来源packages/ui/src/components/dialog/DialogEnhanced.vue | |||
destroyOnClose | boolean | undefined | false | 关闭后延迟卸载默认插槽内容;forceMount 为真时不会卸载。 |
详情声明类型boolean | undefined 字面量
默认值详情
来源packages/ui/src/components/dialog/DialogEnhanced.vue | |||
destroyDelay | number | undefined | 300 | destroyOnClose 启用时,关闭后等待卸载插槽内容的毫秒数。 |
详情声明类型number | undefined 默认值详情
来源packages/ui/src/components/dialog/DialogEnhanced.vue | |||
zIndex | number | undefined | undefined | 显式设置对话框内容面板的 CSS z-index。 |
详情声明类型number | undefined 默认值详情
来源packages/ui/src/components/dialog/DialogEnhanced.vue | |||
class | string | undefined | undefined | 追加到对话框内容面板的自定义 CSS 类。 |
详情声明类型string | undefined 默认值详情
来源packages/ui/src/components/dialog/DialogEnhanced.vue | |||
| 名称 | 签名或类型 | 说明 |
|---|---|---|
@open | [] | 组件挂载时发出,表示 DialogEnhanced 实例已挂载,不表示受控打开状态每次变化。 |
详情声明类型[] 来源packages/ui/src/components/dialog/DialogEnhanced.vue | ||
@close | [] | 关闭请求未被 beforeClose 拒绝时发出;未提供钩子时关闭请求直接通过。 |
详情声明类型[] 来源packages/ui/src/components/dialog/DialogEnhanced.vue | ||
@update:open | [value: boolean] | 已接受的关闭请求以 false 发出,用于将 DialogRoot 的受控打开状态设为关闭。 |
详情声明类型[value: boolean] 字面量
来源packages/ui/src/components/dialog/DialogEnhanced.vue | ||
| 名称 | 签名或类型 | 说明 |
|---|---|---|
#default | {} | 对话框内容;启用 destroyOnClose 后可在关闭延迟结束时卸载。 |
详情声明类型{}来源packages/ui/src/components/dialog/DialogEnhanced.vue | ||
DialogHeader
| 名称 | 类型 | 默认值 | 说明 |
|---|---|---|---|
class | string | undefined | — | 追加到标题区域容器的自定义 CSS 类。 |
详情声明类型string | undefined 默认值详情
来源packages/ui/src/components/dialog/DialogHeader.vue | |||
| 名称 | 签名或类型 | 说明 |
|---|---|---|
#default | {} | 标题、描述或其他头部内容。 |
详情声明类型{}来源packages/ui/src/components/dialog/DialogHeader.vue | ||
DialogOverlay
| 名称 | 类型 | 默认值 | 说明 |
|---|---|---|---|
class | string | undefined | undefined | 追加到背景遮罩原语的自定义 CSS 类。 |
详情声明类型string | undefined 默认值详情
来源packages/ui/src/components/dialog/DialogOverlay.vue | |||
forceMount | boolean | undefined | undefined | 将 force-mount 策略传递给 Reka UI 遮罩原语。 |
详情声明类型boolean | undefined 字面量
默认值详情
来源packages/ui/src/components/dialog/DialogOverlay.vue | |||
asChild | boolean | undefined | false | 将遮罩原语的元素渲染委托给默认插槽中的子元素。 |
详情声明类型boolean | undefined 字面量
默认值详情
来源packages/ui/src/components/dialog/DialogOverlay.vue | |||
pattern | boolean | undefined | false | 为遮罩层添加点阵半色调背景纹理。 |
详情声明类型boolean | undefined 字面量
默认值详情
来源packages/ui/src/components/dialog/DialogOverlay.vue | |||
| 名称 | 签名或类型 | 说明 |
|---|---|---|
#default | {} | 为 asChild 模式提供要渲染的遮罩子元素。 |
详情声明类型{}来源packages/ui/src/components/dialog/DialogOverlay.vue | ||
DialogTitle
| 名称 | 类型 | 默认值 | 说明 |
|---|---|---|---|
class | string | undefined | — | 追加到对话框标题原语的自定义 CSS 类。 |
详情声明类型string | undefined 默认值详情
来源packages/ui/src/components/dialog/DialogTitle.vue | |||
| 名称 | 签名或类型 | 说明 |
|---|---|---|
#default | {} | 对话框的标题文本或内容。 |
详情声明类型{}来源packages/ui/src/components/dialog/DialogTitle.vue | ||
Reka UI 原语
DialogRoot、DialogTrigger、DialogClose 和 DialogPortal 是示例中直接从 reka-ui 导入的原语;DialogContent、DialogHeader、DialogFooter、DialogTitle、DialogDescription、DialogOverlay 和 DialogEnhanced 是 BrutxUI 组件。DialogEnhanced 需要放在 DialogRoot 提供的上下文中使用。
可访问性
- 键盘操作:按
Escape关闭对话框 - 焦点管理:对话框打开时,焦点被限制在对话框内;关闭时恢复焦点
- ARIA 属性:关闭按钮包含屏幕阅读器文本
- 交互元素:拖拽时自动排除交互元素(Input、Button 等)
函数式 API
除了声明式组件,Dialog 还提供命令式调用与 Composable 方式,适合在业务逻辑中快速弹出自定义对话框容器。如需结构化确认框、状态图标或输入提示,请参阅独立的 MessageBox 消息对话框。
showDialog
调用 showDialog 以命令式挂载通用的 Dialog 对话框容器:
import { showDialog } from 'brutx-ui-vue'
const instance = showDialog({
title: '系统设置',
content: '自定义弹层正文内容...',
size: 'default',
draggable: true,
showCloseButton: true,
onCancel: () => {
console.log('对话框已关闭')
},
})
// 手动关闭
// instance.close()常用参数:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
title | string | — | 对话框标题 |
description | string | — | 对话框描述 |
content | string | Component | VNode | (() => ...) | — | 自定义正文内容 |
footer | string | Component | VNode | (() => ...) | — | 自定义底部插槽内容 |
size | 'sm' | 'default' | 'lg' | 'xl' | 'full' | 'default' | 对话框尺寸 |
draggable | boolean | false | 是否开启拖拽 |
resizable | boolean | false | 是否开启缩放 |
fullscreen | boolean | false | 是否全屏展示 |
zIndex | number | — | 自定义弹层层级 |
onCancel | () => void | — | 关闭时的回调钩子 |
返回值: OverlayInstanceHandle<void> — 包含 close()、destroy() 方法及 promise 句柄。
useDialog(Composable)
在组件中使用 useDialog 组合式函数,获得响应式的状态与单例实例管理:
<script setup>
import { useDialog } from 'brutx-ui-vue'
const { show, close, isOpen } = useDialog()
function showMyDialog() {
show({
title: '提示',
content: '这是一个通过 Composable 打开的自定义对话框',
})
}
</script>
<template>
<div class="flex items-center gap-3">
<button @click="showMyDialog">打开对话框</button>
<span v-if="isOpen" class="text-sm font-bold text-brutal-accent">对话框开启中</span>
</div>
</template>TIP
useDialog 返回的 isOpen 属性为 Readonly<Ref<boolean>> 只读响应式视图,状态仅由 Composable 内部统一调度。
useDialogGeometry(空间几何状态控制器)
当需要对自定义弹窗或浮层实现拖拽、缩放与边界约束时,可直接使用底层的 useDialogGeometry 纯空间几何状态控制器:
import { useDialogGeometry } from 'brutx-ui-vue'
const {
contentRef,
position,
size,
contentStyle,
isDragging,
isResizing,
onDragStart,
onResizeStart,
} = useDialogGeometry({
draggable: true,
resizable: true,
bounds: 'viewport',
minWidth: 320,
minHeight: 240,
})- 纯空间几何职责:专注管理位置、尺寸、拖拽、缩放、宽高比与视口/父级边界限制,彻底与业务关闭控制流解耦;
- 只读视图契约:
position与size为只读 Ref,程序化改写请通过setPosition与setSize。
常见问题
Q: 打开对话框后页面还能滚动怎么办?
A: 默认情况下 Dialog 的 modal 属性为 true,打开时会锁定背景滚动。如果遇到背景仍可滚动的情况,请确认没有通过 CSS 手动覆盖了 overflow 属性,或者检查是否有其他全局样式干扰了对话框的遮罩层行为。
Q: 如何通过代码控制对话框的打开和关闭?
A: 使用受控模式:将 Dialog 的 open 属性绑定到一个 ref 变量,然后通过修改该变量来控制对话框状态。也可以监听 update:open 事件来响应对话框的关闭操作(如按 Escape 键或点击遮罩层)。
Q: DialogEnhanced 的拖拽区域不正确,怎样设置拖拽手柄?
A: 通过 drag-handle 属性指定拖拽手柄,可以是 CSS 选择器字符串(如 ".dialog-header")或 DOM 元素引用。确保选择器能正确匹配到对话框内的某个元素,只有按住该元素区域才能拖拽。不设置时,默认整个对话框内容区域可拖拽。