Skip to content

Dialog 对话框

新粗野主义风格的模态对话框,基于 reka-ui 的 Dialog 原语构建。支持遮罩层、关闭按钮和可组合的子组件。

预览

Preview

安装

pnpm dlx brutx-vue@latest add dialog

用法

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

尺寸

通过 DialogContentsize 属性控制对话框的最大宽度。默认值为 defaultmax-w-lg)。

尺寸最大宽度适用场景
smmax-w-sm确认框、简单提示
defaultmax-w-lg标准表单、常规内容
lgmax-w-2xl多列表单、详细设置
xlmax-w-4xl复杂内容、数据展示
fullmax-w-[calc(100vw-2rem)]大幅内容、全屏式交互
vue
<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 用法

支持可拖拽和可调整大小的增强版对话框:

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

Props

Dialog(根组件)

从 reka-ui 的 DialogRoot 重新导出,管理对话框的打开/关闭状态。

属性类型默认值说明
openboolean受控的打开状态
defaultOpenbooleanfalse非受控模式下的默认打开状态
modalbooleantrue是否为模态对话框

DialogTrigger

从 reka-ui 重新导出的触发按钮。

属性类型默认值说明
asChildboolean是否将渲染委托给子元素
asstring'button'渲染的 HTML 元素

DialogContent

属性类型默认值说明
showCloseButtonbooleantrue是否显示关闭按钮
size'sm' | 'default' | 'lg' | 'xl' | 'full''default'对话框尺寸
forceMountboolean强制渲染(用于动画控制)
classstring自定义样式类

DialogClose

从 reka-ui 重新导出的关闭按钮。

属性类型默认值说明
asChildboolean是否将渲染委托给子元素
asstring'button'渲染的 HTML 元素

DialogEnhanced

属性类型默认值说明
draggablebooleanfalse是否可拖拽
dragHandlestring | HTMLElement拖拽手柄(CSS 选择器或元素)
bounds'parent' | 'viewport' | { top, left, right, bottom }'viewport'拖拽边界
initialPosition{ x: number; y: number }初始位置
resizablebooleanfalse是否可调整大小
minWidthnumber200最小宽度
minHeightnumber150最小高度
maxWidthnumber最大宽度
maxHeightnumber最大高度
aspectRationumber宽高比锁定
showCloseButtonbooleantrue是否显示关闭按钮
forceMountboolean强制渲染
fullscreenbooleanfalse全屏模式(占满整个视口)
beforeClose((done) => void) | (() => boolean | Promise<boolean>)关闭前钩子(支持回调模式和 Promise 模式)
destroyOnClosebooleanfalse关闭后销毁内容
zIndexnumber自定义层级
classstring自定义样式类

DialogHeader / DialogFooter / DialogTitle / DialogDescription / DialogOverlay

属性类型默认值说明
classstring自定义样式类

事件

Dialog

事件参数说明
update:open(value: boolean)对话框打开状态变化时触发

DialogEnhanced 事件

事件参数说明
update:open(value: boolean)对话框打开状态变化时触发
open对话框开始打开时触发
opened对话框打开动画完成时触发
close对话框开始关闭时触发
closed对话框关闭动画完成时触发

插槽

Dialog

插槽作用域说明
default{ open: boolean, close: () => void }默认插槽,提供当前打开状态和关闭方法

DialogContent / DialogHeader / DialogFooter / DialogTitle / DialogDescription / DialogOverlay / DialogEnhanced

插槽作用域说明
default默认插槽

可访问性

  • 键盘操作:按 Escape 关闭对话框
  • 焦点管理:对话框打开时,焦点被限制在对话框内;关闭时恢复焦点
  • ARIA 属性:关闭按钮包含屏幕阅读器文本
  • 交互元素:拖拽时自动排除交互元素(Input、Button 等)

函数式 API

除了声明式组件,Dialog 还提供函数式调用方式,适合在业务逻辑中快速弹出对话框。

showDialog

直接调用 showDialog 以编程方式创建并打开一个对话框:

ts
import { showDialog } from 'brutx-ui-vue'

const instance = showDialog({
    title: '确认操作',
    content: '确定要删除这条记录吗?',
    size: 'sm',
    onConfirm: () => {
        // 处理确认逻辑
    },
    onCancel: () => {
        // 处理取消逻辑
    },
})

参数:

参数类型默认值说明
titlestring对话框标题
contentstring对话框内容
size'sm' | 'default' | 'lg' | 'xl' | 'full''default'对话框尺寸
onConfirm() => void确认回调
onCancel() => void取消回调

返回值: 返回对话框实例,包含 close() 方法用于手动关闭。

showMessageBox

调用 showMessageBox 弹出一个确认消息框,返回 Promise:

ts
import { showMessageBox } from 'brutx-ui-vue'

async function handleDelete() {
    const confirmed = await showMessageBox({
        title: '警告',
        content: '此操作不可撤销,确定要继续吗?',
        confirmText: '确定',
        cancelText: '取消',
    })

    if (confirmed) {
        // 用户点击了确认
    }
}

参数:

参数类型默认值说明
titlestring消息框标题
contentstring消息框内容
confirmTextstring'确认'确认按钮文本
cancelTextstring'取消'取消按钮文本
size'sm' | 'default' | 'lg' | 'xl' | 'full''sm'消息框尺寸

返回值: Promise<boolean> — 用户点击确认返回 true,点击取消返回 false

useDialog(Composable)

在组件中使用 useDialog 组合式函数,获得对话框的响应式控制能力:

vue
<script setup>
import { useDialog } from 'brutx-ui-vue'

const { open, close, isOpen } = useDialog()

function showMyDialog() {
    open({
        title: '提示',
        content: '这是一个通过 Composable 打开的对话框',
    })
}
</script>

<template>
    <button @click="showMyDialog">打开对话框</button>
</template>

useMessageBox(Composable)

在组件中使用 useMessageBox 组合式函数,获得消息框的响应式控制能力:

vue
<script setup>
import { useMessageBox } from 'brutx-ui-vue'

const { confirm } = useMessageBox()

async function handleAction() {
    const result = await confirm({
        title: '确认',
        content: '确定要执行此操作吗?',
    })
    if (result) {
        // 用户确认
    }
}
</script>

<template>
    <button @click="handleAction">执行操作</button>
</template>

常见问题

Q: 打开对话框后页面还能滚动怎么办?

A: 默认情况下 Dialogmodal 属性为 true,打开时会锁定背景滚动。如果遇到背景仍可滚动的情况,请确认没有通过 CSS 手动覆盖了 overflow 属性,或者检查是否有其他全局样式干扰了对话框的遮罩层行为。

Q: 如何通过代码控制对话框的打开和关闭?

A: 使用受控模式:将 Dialogopen 属性绑定到一个 ref 变量,然后通过修改该变量来控制对话框状态。也可以监听 update:open 事件来响应对话框的关闭操作(如按 Escape 键或点击遮罩层)。

Q: DialogEnhanced 的拖拽区域不正确,怎样设置拖拽手柄?

A: 通过 drag-handle 属性指定拖拽手柄,可以是 CSS 选择器字符串(如 ".dialog-header")或 DOM 元素引用。确保选择器能正确匹配到对话框内的某个元素,只有按住该元素区域才能拖拽。不设置时,默认整个对话框内容区域可拖拽。

蛮力铸就。