# Modal 弹窗 :::tip 说明 项目使用 `basicModal` 组件(`src/components/Modal/src/BasicModal.vue`)配合 `useModal` hook 实现弹窗。编辑弹窗通过 `v-if` 懒加载,减少首屏渲染负担。 ::: ## 组件架构 ``` src/components/Modal/ ├── src/ │ ├── BasicModal.vue # 主组件(基于 NaiveUI n-modal) │ ├── props.ts # 属性定义 │ ├── type.ts # 类型定义(ModalProps、ModalMethods) │ └── hooks/ │ └── useModalContext.ts # 弹窗上下文 └── index.ts # 导出 useModal 等 ``` ## basicModal 组件 `basicModal` 基于 NaiveUI `n-modal` 封装,通过 `useModal` hook 管理弹窗状态,提供全屏切换、自定义头部、自动 OK/Cancel 按钮等能力: ```vue ``` ```typescript const [modalRegister, { openModal, setSubLoading }] = useModal({ title: '编辑', subBtuText: '确定', width: 600, }); ``` 核心功能: - `useModal` hook 返回 `modalRegister`(绑定到组件 `@register`)和操作方法 - `openModal` 打开弹窗、`setSubLoading` 控制提交按钮 loading - 自动渲染 OK/Cancel 底部按钮,无需手动编写 footer 模板 - `@on-ok` 监听确定按钮点击,`@on-close` 监听关闭事件 ## 实际用法(position 模块) 以岗位管理为例,使用 `basicModal` + `useModal` hook 管理弹窗状态。 ### 父组件(index.vue) ```vue ``` 父组件通过 `ref` 获取子组件实例,调用 `createModalRef.value.openModal()` 打开弹窗。子组件通过 `defineExpose({ openModal })` 暴露该方法。 ### 编辑弹窗(edit.vue) ```vue ``` ## 弹窗数据流 ``` 父组件点击编辑 → positionId = record.id → editVisible = true → nextTick → createModalRef.openModal() ↓ basicModal 显示 → useModal 配置标题和按钮 ↓ edit.vue onMounted → positionId != 0 → setFormData() → 获取详情填充表单 ↓ 用户点击确定 → @on-ok → handleSubmit → formRef.validate() → positionUpdate(formData) → setSubLoading(false) ↓ emit('success') → 父组件 reloadTable() → 表格刷新 ``` ## 确认弹窗 删除等危险操作使用 NaiveUI 的 `useDialog` 组合式函数: ```typescript import { useMessage, useDialog } from 'naive-ui'; const message = useMessage(); const dialog = useDialog(); async function handleDelete(record: Recordable) { let ids = []; if (!record) { ids = selectionData.value.map(({ id }) => id); } dialog.warning({ title: '提示', content: '确定要删除?', positiveText: '确定', negativeText: '取消', onPositiveClick: async () => { record ? await positionDelete(record.id) : await positionBatchDelete(ids); message.success('删除成功'); reloadTable(); }, }); } ``` `dialog.warning` 返回一个对话框实例,用户点击"确定"后执行 `onPositiveClick` 回调。与旧版 `confirm` 不同,不需要 `await` 和 `try/catch`,逻辑全部写在回调中。 :::tip 温馨提示 弹窗组件通过 `v-if` 控制懒加载,首屏不加载弹窗代码。`useModal` 的 `setSubLoading` 控制确定按钮 loading 状态,防止重复提交。`message.success` 和 `dialog.warning` 来自 NaiveUI 的 `useMessage()` 和 `useDialog()` 组合式函数,需要在 `setup` 中调用获取实例。 ::: ## 总结 编辑弹窗使用 `basicModal` + `useModal` hook 管理弹窗状态,通过 `defineExpose({ openModal })` 暴露给父组件调用。`useModal` 返回 `modalRegister` 绑定到 `@register`,以及 `openModal`、`setSubLoading` 等操作方法。表单使用 NaiveUI 的 `n-form` 系列组件,绑定方式为 `v-model:value`,校验字段用 `path` 属性。删除确认使用 `useDialog` 的 `dialog.warning` 回调模式。操作成功后通过 `emit('success')` 通知父组件刷新表格。