对话框
在保留当前页面状态的情况下,告知用户并承载相关操作。
该组件内部集成了 TuiMask 处理遮罩层逻辑,并基于 TuiTyped 组件构建了强大的多色调与外观系统,能够灵活适应各种 UI 风格。
基础用法
Dialog 弹出一个对话框,适合需要定制性更大的场景。
vue
<script setup>
import { ref } from 'vue'
const visible = ref(false)
</script>
<template>
<TuiButton @click="visible = true">打开常规 Dialog</TuiButton>
<TuiDialog
v-model="visible"
title="常规标题"
>
<div class="dialog-content">
这是一段基础内容。
</div>
</TuiDialog>
</template>布局与尺寸
提供了丰富的属性来控制弹窗的显示位置和大小,支持百分比与像素值。
- width: 自定义宽度(支持
40%或300像素值)。 - fullscreen: 开启全屏显示。
- alignCenter: 将弹窗垂直水平居中显示(默认为顶部
15vh偏移)。 - top: 自定义距离顶部的距离。
vue
<script setup>
import { reactive } from 'vue'
const state = reactive({
showFull: false,
showCenter: false,
showCustom: false
})
</script>
<template>
<div class="demo-box">
<TuiButton @click="state.showFull = true">全屏展示</TuiButton>
<TuiButton @click="state.showCenter = true">居中显示</TuiButton>
<TuiButton @click="state.showCustom = true">自定义宽与Top</TuiButton>
</div>
<TuiDialog v-model="state.showFull" title="全屏展示" fullscreen>
内容区域
</TuiDialog>
<TuiDialog v-model="state.showCenter" title="居中显示" alignCenter width="30%">
内容区域垂直居中
</TuiDialog>
<TuiDialog
v-model="state.showCustom"
title="自定义样式"
width="40%"
top="200"
>
宽度 40%,距离顶部 200px
</TuiDialog>
</template>拖拽与定位
通过 draggable 属性可实现弹窗的拖拽功能。
- draggable: 是否开启拖拽。
- positionType: 定义定位策略,可选
transform(推荐, 性能更好)、absolute、fixed。 - dragContainment: 限制拖拽范围在可视区域内。
- resetDragOnClose: 关闭后是否重置位置。
vue
<script setup>
import { ref } from 'vue'
const visible = ref(false)
</script>
<template>
<TuiButton @click="visible = true">打开可拖拽 Dialog</TuiButton>
<TuiDialog
v-model="visible"
title="按住标题拖拽我"
draggable
positionType="transform"
:resetDragOnClose="true"
>
<div>我使用了 transform 定位,拖拽更流畅。</div>
</TuiDialog>
</template>色调与风格
TuiDialog 深度集成了 TuiTyped 组件,通过 type 和 typedConfig 属性,您可以极其方便地配置弹窗的主题色调(如主要、警告、危险等)以及视觉风格(如透明、模糊背景、强弱色调)。
关于 TuiTyped:这是一个专门处理组件色调变体和视觉深度的底层原子组件,它允许组件在不同背景下自动计算最佳的前景色与背景色。
常用色调
通过 type 属性快速切换预设语义色。
vue
<script setup>
import { reactive } from 'vue'
const dialogs = reactive({
primary: false,
success: false,
warning: false,
danger: false
})
</script>
<template>
<div class="demo-gap">
<TuiButton type="primary" @click="dialogs.primary = true">Primary</TuiButton>
<TuiButton type="success" @click="dialogs.success = true">Success</TuiButton>
<TuiButton type="warning" @click="dialogs.warning = true">Warning</TuiButton>
<TuiButton type="danger" @click="dialogs.danger = true">Danger</TuiButton>
</div>
<TuiDialog v-model="dialogs.primary" title="Primary" type="primary">Content</TuiDialog>
<TuiDialog v-model="dialogs.success" title="Success" type="success">Content</TuiDialog>
<TuiDialog v-model="dialogs.warning" title="Warning" type="warning">Content</TuiDialog>
<TuiDialog v-model="dialogs.danger" title="Danger" type="danger">Content</TuiDialog>
</template>高级风格配置 (TypedConfig)
通过 typedConfig 对象,可以控制更细粒度的视觉表现,例如色调强度 (tone) 和透明度 (transparent)。
vue
<script setup>
import { ref } from 'vue'
const visible = ref(false)
const glassConfig = {
transparent: true, // 开启半透明
backgroundBlur: true, // 开启背景模糊
tone: 'strong' // 强色调模式
}
</script>
<template>
<TuiButton @click="visible = true">打开磨砂玻璃风格</TuiButton>
<TuiDialog
v-model="visible"
title="高级风格"
type="primary"
:typedConfig="glassConfig"
>
这是一个带有背景模糊和半透明效果的 Dialog。
</TuiDialog>
</template>嵌套与多层级
支持在一个 Dialog 内部打开另一个 Dialog。TuiDialog 会自动处理层级关系。
vue
<script setup>
import { reactive } from 'vue'
const state = reactive({
outer: false,
inner: false
})
const handleOpenInner = () => {
state.inner = true
}
</script>
<template>
<TuiButton @click="state.outer = true">打开第一层</TuiButton>
<TuiDialog v-model="state.outer" title="第一层 Dialog" width="40%">
<div class="dialog-content">
<p>点击下方按钮打开第二层嵌套。</p>
<TuiButton @click="handleOpenInner">打开第二层</TuiButton>
</div>
</TuiDialog>
<TuiDialog v-model="state.inner" title="第二层 Dialog" width="20%">
<div class="dialog-content">
这是最顶层的弹窗内容。
</div>
</TuiDialog>
</template>API 参考
Props
| 属性名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| modelValue | (v-model) 是否显示 Dialog | Boolean | false |
| title | 标题文本 | String | — |
| width | 弹窗宽度,支持 300 (px) 或 '40%' | String / Number | null |
| top | 距离顶部的偏移量 | String / Number | — |
| alignCenter | 是否垂直居中显示 | Boolean | false |
| center | 是否让弹窗内部的 Header 和 Content 居中对齐 | Boolean | false |
| fullscreen | 是否全屏显示 | Boolean | false |
| modal | 是否需要遮罩层 | Boolean | true |
| draggable | 是否开启头部拖拽 | Boolean | false |
| positionType | 拖拽定位类型,可选 `'transform' | 'absolute' | 'fixed'` |
| dragContainment | 是否将拖拽限制在窗口范围内 | Boolean | true |
| resetDragOnClose | 关闭时是否重置拖拽位置 | Boolean | true |
| type | 语义类型,可选 `'default' | 'primary' | 'success' |
| typedConfig | TuiTyped 配置对象,包含 tone, transparent, backgroundBlur 等 | Object | — |
| customColor | 自定义颜色值,支持 HEX 或 RGB 数组 | String / Array | — |
| showClose | 是否显示关闭图标 | Boolean | true |
| closeIcon | 自定义关闭图标的 Class | String | 'tui-icon ti-times' |
| divider | 是否显示标题与内容之间的分割线 | Boolean | false |
| destroyOnClose | 关闭时是否销毁元素 | Boolean | false |
| lockScroll | 是否锁定背景滚动 | Boolean | true |
| closeOnBackdrop | 点击遮罩层是否关闭 | Boolean | true |
| closeOnEsc | 按下 Esc 键是否关闭 | Boolean | true |
| zIndex | 手动控制层级 | Number | null |
| appendTo | 指定挂载的 DOM 节点选择器 | String | — |
Emits
| 事件名 | 说明 | 回调参数 |
|---|---|---|
| update:modelValue | 绑定值变化时触发 | value: boolean |
| open | Dialog 打开时触发 | — |
| opened | Dialog 打开动画结束时触发 | — |
| close | Dialog 关闭时触发 | — |
| closed | Dialog 关闭动画结束时触发 | — |
| confirm | 确认事件(通常结合 footer 插槽使用) | — |
Slots
| 插槽名 | 说明 |
|---|---|
| default | Dialog 的主体内容 |
| footer | Dialog 底部操作区内容 |
全局交互与层级管控
在多层弹窗嵌套或并存的复杂场景下,TuiDialog 依赖 TechUI 的全局服务(TuiService)来实现智能的堆叠管理:
- ESC 响应 (
escCounter):组件实时监听全局 ESC 信号。当closeOnEsc为true时,组件会响应该信号。 - 智能堆叠判断 (Stack Management):全局服务维护着一个当前活跃弹窗的堆叠栈。当 ESC 触发时,组件会与全局服务进行通信,确保仅有关闭处于最顶层(即最后打开或 z-index 最高)的 Dialog 实例。这种机制完美解决了嵌套弹窗场景下的“误关”问题,保证了交互逻辑的清晰与安全。