---
title: Modal 模态框
description: 用于短阻塞任务的轻量对话框
category: Feedback
status: beta
since: 0.3.4
tags: [modal, dialog, overlay]
syncStatus: reviewed
verified: true
---

## 用法

### 基础
`v-model` 控制显隐，`footer` 插槽放置操作按钮。
::::TuffDemoWrapper{demo="ModalBasicDemo" code-lang="vue"}
---
code: |
  <template>
    <TxButton variant="primary" @click="open = true">打开模态框</TxButton>
    <TxButton variant="ghost" @click="fullscreen = true">打开全屏预览</TxButton>

    <TxModal v-model="open" title="确认同步设置" width="min(92vw, 520px)">
      <p>模态框适合短确认或小型表单。</p>
      <template #footer>
        <TxButton variant="ghost" @click="open = false">取消</TxButton>
        <TxButton variant="primary" @click="open = false">确认同步</TxButton>
      </template>
    </TxModal>

    <TxModal v-model="fullscreen" fullscreen title="发布说明">
      <p>长内容在面板内部滚动，两条栏保持固定。</p>
      <template #footer>
        <TxButton variant="ghost" @click="fullscreen = false">关闭预览</TxButton>
      </template>
    </TxModal>
  </template>
---
::::

### 全屏面板
`fullscreen` 撑满可见视口：正文滚动，头部与底栏固定，底栏避开底部安全区。

```vue
<TxModal v-model="previewOpen" fullscreen :title="current?.name">
  <img :src="current.url" alt="">
  <template #footer>
    <TxButton variant="ghost" @click="previewOpen = false">关闭</TxButton>
  </template>
</TxModal>
```

### 最佳实践

- 只用于确认、单步输入或短决策；需要导航、筛选或长表单时用抽屉或页面。
- 自定义 `header` 时保留可见标题并让 `title` 留空，否则 `aria-labelledby` 会指向不存在的元素。
- 破坏性或最终操作放在 `footer`，次要操作的视觉权重低于主操作。
- `fullscreen` 只用于内容本身占满屏幕的场景（图片、图表预览），短确认不要用。
- 长耗时的异步状态不要只存在模态框内容里；关闭会取消任务时，由父级显式建模取消。

## API 参考

### 属性

| 属性名 | 类型 | 默认值 | 说明 |
|------|------|---------|------|
| `modelValue` | `boolean` | 必填 | 是否显示，用于 `v-model`。 |
| `title` | `string` | `''` | 默认头部标题；非空时与 `aria-labelledby` 关联。 |
| `width` | `string` | `'480px'` | 面板宽度，推荐 `min(92vw, 520px)` 这类响应式值；`fullscreen` 时忽略。 |
| `fullscreen` | `boolean` | `false` | 面板撑满可见视口，去掉圆角与阴影。 |

### 事件

| 事件名 | 参数 | 说明 |
|------|------|------|
| `update:modelValue` | `(value: boolean)` | 请求改变可见状态时触发。 |
| `close` | `()` | 点击遮罩、按 Escape 或点击关闭按钮后触发。 |

### 插槽

| 插槽名 | Props | 说明 |
|------|-------|------|
| `default` | - | 主体内容。 |
| `header` | - | 替换标题区域，保留内置关闭按钮。 |
| `footer` | - | 底部操作区；未提供时不渲染。 |

## 概述

- 遮罩 teleport 到 `body`，打开时从共享 z-index manager 取得新层级，关闭时由 `v-if` 移除。
- 遮罩为 `role="dialog"`、`aria-modal="true"`；打开时获得焦点，关闭或卸载时焦点回到打开前的元素。
- Tab 与 Shift+Tab 在最上层的模态框内循环；即使焦点落到 `body`，底层抽屉也不会响应 Escape。
- 点击遮罩空白、Escape 与关闭按钮依次派发 `update:modelValue(false)` 与 `close`。
- `fullscreen` 只改变布局，对话框语义与焦点管理不变；没有可点击的遮罩空白，因此头部或底栏必须保留可见的关闭入口。
- `TModal` 把 props、attrs、事件与 `default` / `header` / `footer` 插槽转发给 `TxModal`。

## 技术实现

- 全屏面板在支持时使用 `100dvh` 高度，底栏下内边距带上 `safe-area-inset-bottom`。
- 源码：`packages/tuffex/packages/components/src/modal/`（`TxModal.vue` 与包装组件 `TModal.vue`）。

<TuffDocSourceLink />
