# 模态框与抽屉

模态框基于原生 <dialog>，抽屉是右侧滑出的面板。用 data-zh-open / data-zh-close 声明即可，也可用 ZhaoUI.open / close / dialog 调用。

**依赖**：`zhaoui.css` 与 `zhaoui.js`（原生 HTML、CSS、JS，不需要框架或 jQuery）。

## 用法

```html
<button class="zh-btn" data-zh-open="#dlg">打开</button>
<dialog class="zh-modal" id="dlg" aria-labelledby="dlgT" data-zh-backdrop-close>
  <header id="dlgT">确认删除</header>
  <div class="body">删除后无法恢复。</div>
  <footer>
    <button class="zh-btn" data-zh-close>取消</button>
    <button class="zh-btn primary" data-zh-close>确定</button>
  </footer>
</dialog>

<button class="zh-btn" data-zh-open="#drw">打开抽屉</button>
<aside class="zh-drawer" id="drw" aria-label="详情">
  <button class="zh-btn text" data-zh-close>关闭</button>
  <p>抽屉内容</p>
</aside>

<script>
ZhaoUI.dialog({ title: '删除文章？', content: '删除后无法恢复', danger: true })
  .then(function (ok) { if (ok) { /* 执行删除 */ } });
</script>
```

## 样式类

`zh-modal`、`zh-drawer`

## 属性

| 属性 | 用在 | 取值 | 说明 |
|---|---|---|---|
| `data-zh-open` | 按钮或链接 | 目标的 CSS 选择器，如 #dlg | 点击后打开目标对话框或抽屉，并记住触发元素，关闭后焦点回到它 |
| `data-zh-close` | 对话框或抽屉内的按钮 | 留空，或目标选择器 | 点击后关闭所在的对话框或抽屉；写了选择器则关闭那个目标 |
| `data-zh-backdrop-close` | dialog.zh-modal | 无 | 点击遮罩（对话框以外的区域）关闭 |

## 方法

- `ZhaoUI.open(target, opener?)`：打开对话框或抽屉。target 是元素或选择器；opener 是关闭后要聚焦回去的元素（可选）
- `ZhaoUI.close(target)`：关闭对话框或抽屉
- `ZhaoUI.dialog({ title, content, ok, cancel, danger, backdropClose })`：弹出确认框，返回 Promise：点确定为 true，取消、Esc 为 false。选项：title 标题；content 正文（纯文本，要放标签请传 DOM 节点）；ok 确定按钮文字（默认「确定」）；cancel 取消按钮文字（默认「取消」，传 false 则不显示取消）；danger 为 true 时确定按钮用危险样式（红色），否则是主色；backdropClose 为 true 时点遮罩也算取消。例：ZhaoUI.dialog({ title: '删除文章？', content: '删除后无法恢复', ok: '删除', cancel: '再想想', danger: true }).then(function (yes) { if (yes) remove(); })

## 事件

| 事件 | 触发于 | detail | 说明 |
|---|---|---|---|
| `zh:open` | 抽屉 | 无 | 抽屉打开后触发（冒泡） |
| `zh:close` | 抽屉 | 无 | 抽屉关闭后触发（冒泡）。模态框用原生 close 事件 |

## 无障碍

- 模态框使用原生 <dialog>.showModal()：浏览器负责焦点限制、Esc 关闭与背景不可交互
- 抽屉打开时限制 Tab 焦点在抽屉内，Esc 关闭；关闭后带 inert 与 aria-hidden，不会被键盘聚焦到
- 关闭后焦点回到触发元素（包括 Safari，它点击按钮时不会给按钮焦点，所以库自己记住了触发元素）
- 对话框请用 aria-labelledby 指向标题；ZhaoUI.dialog 已自动处理

## 常见问题

### 模态框与抽屉是什么？

模态框基于原生 <dialog>，抽屉是右侧滑出的面板。用 data-zh-open / data-zh-close 声明即可，也可用 ZhaoUI.open / close / dialog 调用。

### 怎么使用模态框与抽屉？

先在页面里引入 zhaoui.css 和 zhaoui.js（放在 </body> 前，不加 defer），再照本页「用法」里的标记书写；需要用代码控制时，用「方法」里列出的接口。

### 模态框与抽屉有哪些事件？

zh:open（抽屉打开后触发（冒泡））；zh:close（抽屉关闭后触发（冒泡）。模态框用原生 close 事件）。

### 模态框与抽屉有哪些方法？

ZhaoUI.open(target, opener?)：打开对话框或抽屉。target 是元素或选择器；opener 是关闭后要聚焦回去的元素（可选）；ZhaoUI.close(target)：关闭对话框或抽屉；ZhaoUI.dialog({ title, content, ok, cancel, danger, backdropClose })：弹出确认框，返回 Promise：点确定为 true，取消、Esc 为 false。选项：title 标题；content 正文（纯文本，要放标签请传 DOM 节点）；ok 确定按钮文字（默认「确定」）；cancel 取消按钮文字（默认「取消」，传 false 则不显示取消）；danger 为 true 时确定按钮用危险样式（红色），否则是主色；backdropClose 为 true 时点遮罩也算取消。例：ZhaoUI.dialog({ title: '删除文章？', content: '删除后无法恢复', ok: '删除', cancel: '再想想', danger: true }).then(function (yes) { if (yes) remove(); })。

### 模态框与抽屉支持键盘和读屏吗？

模态框使用原生 <dialog>.showModal()：浏览器负责焦点限制、Esc 关闭与背景不可交互；抽屉打开时限制 Tab 焦点在抽屉内，Esc 关闭；关闭后带 inert 与 aria-hidden，不会被键盘聚焦到；关闭后焦点回到触发元素（包括 Safari，它点击按钮时不会给按钮焦点，所以库自己记住了触发元素）。

### 模态框与抽屉需要依赖框架吗？

不需要。ZhaoUI 是原生 HTML、CSS 和 JavaScript，不依赖 jQuery、Vue 或 React。
