# Modal 弹窗
:::tip 说明
项目提供 `BasicModal` 组件(`src/components/Modal/src/basicModal.vue`)和原生 `a-modal` 两种弹窗用法。编辑弹窗通过 `defineAsyncComponent` 懒加载,减少首屏渲染负担。
:::
## 组件架构
```
src/components/Modal/
├── src/
│ ├── basicModal.vue # 主组件(基于 a-modal)
│ ├── props.ts # 属性定义
│ ├── type/index.ts # 类型定义(ModalProps、ModalMethods)
│ ├── hooks/
│ │ ├── useModal.ts # 弹窗 Hook
│ │ └── useModalDrag.ts # 弹窗拖拽
│ └── components/
│ ├── Modal.tsx # 弹窗渲染组件
│ └── ModalClose.vue # 关闭按钮组件
└── index.ts # 导出 useModal 等
```
## BasicModal 组件
`BasicModal` 基于 `a-modal` 封装,提供全屏切换、自定义头部、提交按钮等能力:
```vue
```
核心功能:
- 自定义头部(标题 + 全屏/关闭按钮)
- 提交按钮自动 loading(`setSubLoading`)
- `setProps` 动态修改弹窗属性
- `openModal` / `closeModal` 控制显隐
## 实际用法(position 模块)
以岗位管理为例,实际使用原生 `a-modal` + `defineAsyncComponent` 懒加载:
### 父组件(index.vue)
```vue
```
`defineAsyncComponent` 实现懒加载:首屏不加载弹窗组件,首次打开时才加载,加载完成后缓存。
### 编辑弹窗(edit.vue)
```vue
正常
停用
```
## 弹窗数据流
```
父组件点击编辑 → positionId = id → editVisible = true
↓
edit.vue onMounted → positionId != 0 → setFormData() → 获取详情填充表单
↓
用户修改 → submit → useLockFn(防重复) → formRef.validate() → positionUpdate(formData)
↓
emit('success') → 父组件 reloadTable() → 表格刷新
```
## 确认弹窗
删除等危险操作使用 Ant Design Vue 的 `Modal.confirm`:
```typescript
import { Modal, message } from 'ant-design-vue';
async function handleDelete(id) {
let ids = [];
if (!id) {
ids = selectionData.value.map(({ id }) => id);
}
Modal.confirm({
title: '提示',
content: '确定要删除?',
onOk: async () => {
id ? await positionDelete(id) : await positionBatchDelete(ids);
message.success('删除成功');
reloadTable();
},
});
}
```
`Modal.confirm` 返回一个引用,用户点击取消时不会执行 `onOk` 回调。
## v-model:visible 双向绑定
弹窗使用 `v-model:visible` 实现父子组件双向绑定:
```vue
```
:::tip 温馨提示
弹窗组件通过 `defineAsyncComponent(() => import('./edit.vue'))` 懒加载,首屏不加载弹窗代码。`useLockFn` 将 `isLock` 绑定按钮的 `:loading` 属性,防止重复提交。关闭弹窗时通过 `v-model:visible` 自动同步父子状态。
:::
## 总结
编辑弹窗使用 `a-modal` + `defineAsyncComponent` 懒加载,通过 `v-model:visible` 双向绑定显隐状态,`useLockFn` 防重复提交。父组件通过 `positionId` prop 传递编辑行 ID,子组件在 `onMounted` 中判断并加载详情数据。操作成功后 `emit('success')` 通知父组件刷新表格。确认弹窗使用 Ant Design Vue 的 `Modal.confirm`。