@tker/popup
v1.0.6
Published
一个基于适配器模式的 Vue3 弹窗管理库,支持模态框、抽屉、消息提示和通知等多种弹窗类型。
Readme
@tker/popup
一个基于适配器模式的 Vue3 弹窗管理库,支持模态框、抽屉、消息提示和通知等多种弹窗类型。
特性
- 🎯 适配器模式:支持多种 UI 框架适配(Naive UI、Element Plus 等)
- 🔧 类型安全:完整的 TypeScript 支持
- 🚀 高性能:组件缓存机制,避免重复渲染
- 📦 轻量级:模块化设计,按需加载
- 🎨 灵活配置:支持全局和实例级配置
- 🔄 生命周期管理:完整的弹窗生命周期控制
项目结构
src/
├── components/ # 组件目录
│ ├── PopupProvider.vue # 弹窗渲染提供者
│ └── adapter/ # 适配器组件
│ └── naive-ui/ # Naive UI 适配器
│ ├── modal/ # 模态框适配器
│ ├── drawer/ # 抽屉适配器
│ ├── message/ # 消息适配器
│ └── notification/ # 通知适配器
├── composables/ # 组合式 API
│ └── usePopup.ts # 核心 API 入口
├── core/ # 核心管理器
│ ├── PopupManager.ts # 弹窗管理器
│ ├── AdaptManager.ts # 适配器管理器
│ ├── InstanceManager.ts # 实例管理器
│ └── Adapter.ts # 适配器基类
├── typing/ # 类型定义
│ ├── popup.ts # 弹窗类型
│ ├── adapter.ts # 适配器类型
│ └── index.ts # 类型导出
├── utils/ # 工具函数
│ └── helpers.ts # 辅助函数
└── index.ts # 主入口文件安装
pnpm add @tker/popup推荐的项目组织方式
为了更好地组织 popup 相关代码,建议采用以下目录结构:
src/
├── shared/
│ └── popup/
│ └── index.ts # 导出 setupPopup 函数
├── App.vue # 在根组件中使用 PopupProvider
├── main.ts # 初始化时调用 setupPopup
└── router/
│ └── index.ts # 路由配置1. 创建 popup 配置目录
将 popup 相关的适配器配置集中管理:
src/shared/popup/index.ts - 初始化配置
import {
getPopupManager,
NDrawerAdapter,
NMessageAdapter,
NModalAdapter,
NNotificationAdapter,
} from "@tker/popup";
import { NMessageProvider, NNotificationProvider } from "naive-ui";
/**
* 初始化 Popup 配置
*/
export function setupPopup(): void {
const manager = getPopupManager();
// 配置模态框适配器
manager.setModalAdapter({
render: NModalAdapter,
});
// 配置消息适配器(需要 provider)
manager.setMessageAdapter({
render: NMessageAdapter,
provider: NMessageProvider,
});
// 配置通知适配器(需要 provider)
manager.setNotificationAdapter({
render: NNotificationAdapter,
provider: NNotificationProvider,
});
// 配置抽屉适配器
manager.setDrawerAdapter({
render: NDrawerAdapter,
});
}说明:
NModalAdapter、NDrawerAdapter:内置的 NaiveUI 模态框和抽屉适配器NMessageAdapter、NNotificationAdapter:内置的 NaiveUI 消息和通知适配器NMessageProvider、NNotificationProvider:NaiveUI 的 Provider 组件,用于提供上下文
2. 在 App.vue 中使用 PopupProvider
<script setup lang="ts">
import { PopupProvider } from "@tker/popup";
</script>
<template>
<popup-provider />
<router-view />
</template>3. 在 main.ts 中初始化
import { createApp } from "vue";
import App from "./App.vue";
import { setupPopup } from "./shared/popup";
import { setupRouter } from "./router";
const app = createApp(App);
setupRouter(app);
setupPopup();
app.mount("#app");这种组织方式的优点
- 职责分离:popup 配置独立于业务组件
- 易于维护:适配器配置集中管理
- 初始化顺序清晰:
main.ts中统一调用setupPopup() - 便于切换 UI 库:只需修改
setupPopup中的适配器配置
内置 NaiveUI 适配器
框架提供以下内置适配器,可从 @tker/popup 直接导入:
import {
NModalAdapter,
NDrawerAdapter,
NMessageAdapter,
NNotificationAdapter,
Confirm,
Prompt,
} from "@tker/popup";| 适配器 | 说明 | 需要 Provider |
|--------|------|---------------|
| NModalAdapter | 模态框适配器 | 否 |
| NDrawerAdapter | 抽屉适配器 | 否 |
| NMessageAdapter | 消息适配器 | 需要 NMessageProvider |
| NNotificationAdapter | 通知适配器 | 需要 NNotificationProvider |
| Confirm | 确认对话框组件 | 通过 NModalAdapter 渲染 |
| Prompt | 输入对话框组件 | 通过 NModalAdapter 渲染 |
注意:Message 和 Notification 需要配置 Provider 才能正常工作:
manager.setMessageAdapter({
render: NMessageAdapter,
provider: NMessageProvider, // 必须提供
});
manager.setNotificationAdapter({
render: NNotificationAdapter,
provider: NNotificationProvider, // 必须提供
});快速开始
1. 配置适配器(旧方式,推荐使用 setupPopup)
如果不想使用 setupPopup 函数,也可以直接在 main.ts 中配置:
import { createApp } from "vue";
import {
PopupProvider,
getPopupManager,
NModalAdapter,
NDrawerAdapter,
NMessageAdapter,
NNotificationAdapter,
} from "@tker/popup";
import { NMessageProvider, NNotificationProvider } from "naive-ui";
const app = createApp(App);
// 获取弹窗管理器并配置适配器
const popupManager = getPopupManager();
// 配置各类型适配器
popupManager.setModalAdapter({ render: NModalAdapter });
popupManager.setDrawerAdapter({ render: NDrawerAdapter });
popupManager.setMessageAdapter({
render: NMessageAdapter,
provider: NMessageProvider,
});
popupManager.setNotificationAdapter({
render: NNotificationAdapter,
provider: NNotificationProvider,
});
app.mount("#app");2. 在模板中添加 PopupProvider
<template>
<div id="app">
<!-- 你的应用内容 -->
<router-view />
<!-- 弹窗提供者 -->
<PopupProvider />
</div>
</template>3. 使用弹窗 API
<script setup>
import {
modal,
drawer,
message,
notification,
alert,
confirm,
prompt
} from '@tker/popup'
// 模态框
const openModal = async () => {
const result = modal({
content: '这是一个模态框',
popupOptions: {
title: '标题'
}
})
// 通过 promise 属性获取用户操作结果
// userAction 的值取决于 content 的类型:
// - 当 content 为字符串时:positive 返回 true,negative 返回 false
// - 当 content 为 Confirm 组件时:positive 返回 true,negative 返回 false
// - 当 content 为 Prompt 组件时:positive 返回输入的值,negative 返回 false
// - 当 content 为自定义组件时:返回值由组件内部的 setPositive/setNegative 函数决定
const userAction = await result.promise
if (userAction) {
console.log('用户确认了操作,返回值:', userAction)
} else {
console.log('用户取消了操作')
}
}
// 抽屉
const openDrawer = () => {
drawer({
content: '抽屉内容',
popupOptions: {
title: '抽屉标题',
placement: 'right'
}
})
}
// 消息提示
const showMessage = () => {
message('操作成功', 'success', 3000)
}
// 通知
const showNotification = () => {
notification('通知内容', '通知标题', 'info', 5000)
}
// 警告框
const showAlert = () => {
alert('这是一个警告信息', '警告')
}
// 确认框
const showConfirm = async () => {
const confirmResult = confirm('确定要删除吗?', '确认删除')
// confirm 的 userChoice 值:positive 返回 true,negative 返回 false
const userChoice = await confirmResult.promise
if (userChoice) {
console.log('用户确认删除')
}
}
// 输入框
const showPrompt = async () => {
const promptResult = prompt('请输入您的姓名', '默认值')
// prompt 的 userInput 值:positive 返回用户输入的字符串,negative 返回 false
const userInput = await promptResult.promise
if (userInput) {
console.log('用户输入:', userInput)
}
}
</script>API 参考
基础 API
modal(config)
创建模态框,返回PopupResult对象
modal({
content: Component | string | VNode,
props?: Record<string, any>,
popupOptions?: {
title?: string,
width?: string | number,
closable?: boolean,
maskClosable?: boolean
}
}): PopupResult<'modal'>PopupResult 接口
interface PopupResult<T> {
id: string; // 弹窗实例ID
promise: Promise<any>; // 用户操作结果的Promise
close: () => void; // 关闭弹窗的方法
update: (config: Partial<PopupOptionsMap[T]>) => void; // 更新弹窗配置的方法
}userAction 返回值说明
result.promise 解析后的 userAction 值取决于 content 参数的类型:
| content 类型 | positive 按钮返回值 | negative 按钮返回值 | 说明 |
|-------------|-------------------|-------------------|------|
| 字符串 | true | false | 默认的确认/取消行为 |
| Confirm 组件 | true | false | 确认对话框的标准返回值 |
| Prompt 组件 | 用户输入的值 | false | 输入对话框返回用户输入内容 |
| 自定义组件 | 由 setPositive() 决定 | 由 setNegative() 决定 | 组件内部可自定义返回值 |
示例:
// 字符串内容
const result1 = modal({ content: '确认删除?' })
const action1 = await result1.promise // true 或 false
// Prompt 组件
const result2 = modal({ content: Prompt, props: { placeholder: '请输入名称' } })
const action2 = await result2.promise // 用户输入的字符串 或 false
// 自定义组件
const result3 = modal({ content: MyCustomComponent })
const action3 = await result3.promise // 由组件内 setPositive/setNegative 决定drawer(config)
创建抽屉,返回PopupResult对象
drawer({
content: Component | string | VNode,
props?: Record<string, any>,
popupOptions?: {
title?: string,
placement?: 'left' | 'right' | 'top' | 'bottom',
width?: string | number,
height?: string | number,
closable?: boolean,
maskClosable?: boolean
}
}): PopupResult<'drawer'>message(configOrContent, type?, duration?)
显示消息提示
参数:
configOrContent: 消息内容(字符串)或完整配置对象(MessageProps)type: 消息类型('error' | 'info' | 'success' | 'warning')duration: 显示时长(毫秒)
返回: PopupResult<'message'>
多种传参方式:
// 方式1:字符串 + 可选参数
message('操作成功', 'success', 3000)
// 方式2:配置对象
message({
content: '操作成功',
type: 'success',
duration: 3000,
position: 'top',
showIcon: true
})类型定义:
message(
configOrContent: MessageProps | string,
type?: 'success' | 'error' | 'warning' | 'info',
duration?: number
): PopupResult<'message'>
interface MessageProps {
duration?: number;
type?: 'error' | 'info' | 'success' | 'warning';
showIcon?: boolean;
position?: PopupPositionValue;
content?: string;
}notification(configOrContent?, title?, type?, duration?)
显示通知
参数:
configOrContent: 通知内容(字符串)或完整配置对象(NotificationProps)title: 通知标题type: 通知类型('error' | 'info' | 'success' | 'warning')duration: 显示时长(毫秒)
返回: PopupResult<'notification'>
多种传参方式:
// 方式1:字符串 + 可选参数
notification('系统更新完成', '系统通知', 'success', 5000)
// 方式2:配置对象
notification({
content: '系统更新完成',
title: '系统通知',
type: 'success',
duration: 5000,
position: 'top-right'
})类型定义:
notification(
configOrContent?: NotificationProps | string,
title?: string,
type?: 'success' | 'error' | 'warning' | 'info',
duration?: number
): PopupResult<'notification'>
interface NotificationProps {
title?: string;
duration?: number;
position?: NotificationPosition;
type?: 'error' | 'info' | 'success' | 'warning';
content?: string;
}便捷方法
消息便捷方法
success(content: string, duration?: number)
error(content: string, duration?: number)
warning(content: string, duration?: number)
info(content: string, duration?: number)通知便捷方法
successNotification(content: string, title?: string, duration?: number)
errorNotification(content: string, title?: string, duration?: number)
warningNotification(content: string, title?: string, duration?: number)
infoNotification(content: string, title?: string, duration?: number)对话框方法
// 警告框
alert(
configOrContent: Omit<AlertProps, "title"> | string,
title?: string
): PopupResult<'modal'>
**参数:**
- `configOrContent`: 警告内容(字符串)或完整配置对象(AlertProps)
- `title`: 警告标题(可选)
**返回:** `PopupResult<'modal'>`
**多种传参方式:**
```typescript
// 方式1:字符串 + 可选标题
alert('操作失败,请重试', '错误提示')
// 方式2:配置对象
alert({
content: '操作失败,请重试',
positiveText: '我知道了'
}, '错误提示')类型定义:
interface AlertProps {
positiveText?: string;
content?: string;
}// 确认框 confirm( configOrContent: Omit<ConfirmProps, "title"> | string, title?: string ): PopupResult<'modal'>
参数:
configOrContent: 确认内容(字符串)或完整配置对象(ConfirmProps)title: 确认标题(可选)
返回: PopupResult<'modal'>
多种传参方式:
// 方式1:字符串 + 可选标题
confirm('确定要删除这条记录吗?', '删除确认')
// 方式2:配置对象
confirm({
content: '确定要删除这条记录吗?',
positiveText: '确定删除',
negativeText: '取消'
}, '删除确认')类型定义:
interface ConfirmProps {
title?: string;
negativeText?: string;
positiveText?: string;
content?: string;
}// 输入框 prompt( configOrTitle: PromptProps | string, defaultValue?: string ): PopupResult<'modal'>
参数:
configOrTitle: 输入框标题(字符串)或完整配置对象(PromptProps)defaultValue: 默认输入值(可选)
返回: PopupResult<'modal'>
多种传参方式:
// 方式1:字符串标题 + 默认值
prompt('请输入您的姓名', '张三')
// 方式2:配置对象
prompt({
title: '请输入您的姓名',
defaultValue: '张三',
placeholder: '请输入姓名',
type: 'text',
maxlength: 20,
validate: (value) => {
if (!value.trim()) return '姓名不能为空'
if (value.length < 2) return '姓名至少2个字符'
return undefined
}
})类型定义:
interface PromptProps {
title?: string;
type?: 'password' | 'text' | 'textarea';
negativeText?: string;
positiveText?: string;
defaultValue?: string;
placeholder?: string;
maxlength?: number;
size?: 'large' | 'medium' | 'small' | 'tiny';
validate?: (value: string) => string | undefined;
}管理方法
// 关闭所有弹窗
closeAll(type?: PopupType)
// 创建关闭事件发射器
createCloseEmitter(): () => boolean
// 创建销毁事件发射器
createDestroyEmitter(): () => boolean
// 创建离开后事件发射器
createAfterLeaveEmitter(): () => void自定义适配器
创建自定义适配器
本库支持创建自定义适配器来扩展弹窗功能,适配不同的UI框架或实现特定的弹窗效果。
1. 基础适配器结构
import { getPopupManager } from '@tker/popup'
import { defineComponent } from 'vue'
// 创建适配器组件
const MyCustomAdapter = defineComponent({
name: 'MyCustomAdapter',
props: {
content: String,
title: String,
// 其他自定义属性
},
setup(props) {
// 适配器逻辑实现
return () => {
// 渲染逻辑
};
}
});
// 注册适配器
const popupManager = getPopupManager()
popupManager.setModalAdapter({
render: MyCustomAdapter,
maxInstance: 5, // 可选:最大实例数
closeAnimationEventName: 'afterLeave' // 可选:关闭动画事件名
})2. 适配器类型定义
// 适配器选项接口
interface AdapterOptions<T extends keyof PopupOptionsMap> {
render: AdapterRender; // 渲染函数或组件
maxInstance?: number; // 最大实例数
closeAnimationEventName?: string; // 关闭动画事件名
provider?: AdapterProvider | Component; // 提供者组件
}
// 渲染类型
type AdapterRender =
| Component // Vue组件
| VNode // 虚拟节点
| (() => Component | Promise<Component> | VNode | Promise<VNode>); // 渲染函数3. 实际示例:Element Plus 适配器
// ElementMessageAdapter.vue
<template>
<div ref="messageRef"></div>
</template>
<script setup lang="ts">
import { ElMessage } from 'element-plus';
import { onMounted } from 'vue';
import { createAfterLeaveEmitter } from '@tker/popup';
interface MessageProps {
content: string;
type?: 'success' | 'warning' | 'info' | 'error';
duration?: number;
showClose?: boolean;
}
const props = withDefaults(defineProps<MessageProps>(), {
type: 'info',
duration: 3000,
showClose: false
});
onMounted(() => {
const instance = ElMessage({
message: props.content,
type: props.type,
duration: props.duration,
showClose: props.showClose,
onClose: createAfterLeaveEmitter() // 重要:通知弹窗系统关闭
});
});
</script>// 注册 Element Plus 适配器
import { getPopupManager } from '@tker/popup'
import ElementMessageAdapter from './ElementMessageAdapter.vue'
const popupManager = getPopupManager()
popupManager.setMessageAdapter({
render: ElementMessageAdapter,
maxInstance: 10
})4. 适配器最佳实践
- 生命周期管理:确保在适配器组件中正确处理关闭事件
import {
createAfterLeaveEmitter,
createPositiveEmitter,
createNegativeEmitter,
createCloseEmitter
} from '@tker/popup';
// 关闭动画完成后的回调
const onAfterLeave = createAfterLeaveEmitter();
// 直接关闭弹窗
const close = createCloseEmitter();
// 确认按钮处理器
const positiveEmitter = createPositiveEmitter();
const handlePositiveClick = async () => {
const result = await positiveEmitter(); // 执行用户定义的确认逻辑
if (result !== undefined) {
close(); // 只有当返回值不为undefined时才关闭弹窗
}
};
// 取消按钮处理器
const negativeEmitter = createNegativeEmitter();
const handleNegativeClick = async () => {
const result = await negativeEmitter(); // 执行用户定义的取消逻辑
if (result !== undefined) {
close(); // 只有当返回值不为undefined时才关闭弹窗
}
};- 类型安全:为适配器定义明确的Props接口
interface CustomAdapterProps {
content: string;
title?: string;
// 其他属性
}- 错误处理:适配器应该处理可能的错误情况
const MyAdapter = defineComponent({
setup(props) {
try {
// 适配器逻辑
} catch (error) {
console.error('适配器错误:', error);
}
}
});- 性能优化:合理设置maxInstance避免过多实例
popupManager.setMessageAdapter({
render: MessageAdapter,
maxInstance: 5 // 限制最大实例数
})适配器管理方法
弹窗管理器提供了便捷的适配器设置方法:
import { getPopupManager } from '@tker/popup'
const popupManager = getPopupManager()
// 通用适配器注册方法
popupManager.addAdapter({
type: 'modal', // 弹窗类型
render: MyModalAdapter, // 渲染组件
maxInstance: 5, // 最大实例数
})
// 便捷的特定类型适配器设置方法
popupManager.setModalAdapter({ render: MyModalAdapter })
popupManager.setDrawerAdapter({ render: MyDrawerAdapter })
popupManager.setMessageAdapter({ render: MyMessageAdapter })
popupManager.setNotificationAdapter({ render: MyNotificationAdapter })完整配置示例
import { getPopupManager } from '@tker/popup'
import MyModalAdapter from './adapters/MyModalAdapter.vue'
import MyDrawerAdapter from './adapters/MyDrawerAdapter.vue'
import MyMessageAdapter from './adapters/MyMessageAdapter.vue'
import MyNotificationAdapter from './adapters/MyNotificationAdapter.vue'
import MyAlertAdapter from './adapters/MyAlertAdapter.vue'
import MyConfirmAdapter from './adapters/MyConfirmAdapter.vue'
import MyPromptAdapter from './adapters/MyPromptAdapter.vue'
const popupManager = getPopupManager()
// 配置所有类型的适配器
popupManager.setModalAdapter({ render: MyModalAdapter, maxInstance: 3 })
popupManager.setDrawerAdapter({ render: MyDrawerAdapter, maxInstance: 2 })
popupManager.setMessageAdapter({ render: MyMessageAdapter, maxInstance: 10 })
popupManager.setNotificationAdapter({ render: MyNotificationAdapter, maxInstance: 8 })
配置选项
全局配置
import { createPopupManager } from '@tker/popup'
// 创建带配置的弹窗管理器
const popupManager = createPopupManager({
defaultZIndex: 1000,
enableMemoryOptimization: true
})
// 或者使用默认管理器
import { getPopupManager } from '@tker/popup'
const manager = getPopupManager()TypeScript 支持
库提供完整的 TypeScript 类型定义:
import type {
PopupInstance,
PopupResult,
ModalConfig,
DrawerConfig,
MessageConfig,
NotificationConfig
} from '@tker/popup'Emitter 机制详解
核心概念
createPositiveEmitter 和 createNegativeEmitter 是弹窗系统中的核心机制,用于处理用户的确认和取消操作。它们的设计目的是让开发者能够在弹窗中执行异步操作,并根据操作结果决定是否关闭弹窗。
confirm vs modal 的选择
使用 confirm:
- 简单的确认/取消场景
- 返回值固定为
true(确认)或false(取消) - 内置标准的确认对话框样式
- 适用于删除确认、操作确认等标准场景
使用 modal + 自定义组件:
- 需要复杂交互的场景
- 需要自定义返回值的场景
- 需要在确认前执行异步验证或操作
- 需要自定义UI和交互逻辑
// ✅ 推荐:简单确认使用confirm
const deleteConfirm = await confirm('确定删除吗?', '删除确认');
if (await deleteConfirm.promise) {
// 用户确认删除
}
// ✅ 推荐:复杂场景使用modal
const formResult = await modal({
content: FormComponent,
props: { initialData }
});
const formData = await formResult.promise; // 可以是任何自定义数据工作原理
// 1. 简单确认场景 - 使用confirm
const result = await confirm(
'确定要删除这个文件吗?',
'删除确认'
);
const userChoice = await result.promise; // true或false
// 2. 复杂场景 - 使用modal + 自定义组件
const complexResult = await modal({
title: '高级操作',
content: CustomComponent,
props: { data: someData }
});
// 在CustomComponent中使用setPositive/setNegative
// 可以执行复杂的异步逻辑并返回自定义结果// 2. 在适配器中使用emitter
const positiveEmitter = createPositiveEmitter();
const negativeEmitter = createNegativeEmitter();
const handlePositiveClick = async () => {
loading.value = true;
try {
const result = await positiveEmitter(); // 调用用户定义的positive函数
if (result !== undefined) {
close(); // 只有返回值不为undefined时才关闭弹窗
}
} finally {
loading.value = false;
}
};返回值处理规则
- 返回
undefined:弹窗保持打开状态,通常用于验证失败或操作失败的情况 - 返回任何其他值:弹窗将关闭,返回值会作为 Promise 的 resolve 值
- 抛出异常:弹窗保持打开状态,异常需要在适配器中处理
使用场景
- 表单验证:在确认前验证表单数据
- 异步操作:执行网络请求、文件操作等
- 用户确认:二次确认重要操作
- 条件关闭:根据业务逻辑决定是否关闭弹窗
完整适配器示例
以下是一个完整的模态框适配器示例,展示了如何正确使用 emitter 机制:
<template>
<div class="modal-overlay" v-if="visible">
<div class="modal-content">
<div class="modal-header">
<h3>{{ title }}</h3>
</div>
<div class="modal-body">
<slot>{{ content }}</slot>
</div>
<div class="modal-footer">
<button
v-if="negativeText"
@click="handleNegativeClick"
:disabled="loading"
class="btn btn-cancel"
>
{{ negativeText }}
</button>
<button
v-if="positiveText"
@click="handlePositiveClick"
:disabled="loading"
class="btn btn-confirm"
>
<span v-if="loading">处理中...</span>
<span v-else>{{ positiveText }}</span>
</button>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import {
createPositiveEmitter,
createNegativeEmitter,
createCloseEmitter,
createAfterLeaveEmitter
} from '@tker/popup';
interface Props {
visible?: boolean;
title?: string;
content?: string;
positiveText?: string;
negativeText?: string;
}
withDefaults(defineProps<Props>(), {
visible: false,
positiveText: '确定',
negativeText: '取消'
});
const loading = ref(false);
// 创建emitter
const positiveEmitter = createPositiveEmitter();
const negativeEmitter = createNegativeEmitter();
const close = createCloseEmitter();
const onAfterLeave = createAfterLeaveEmitter();
// 确认按钮点击处理
const handlePositiveClick = async () => {
loading.value = true;
try {
const result = await positiveEmitter();
// 只有当返回值不为undefined时才关闭弹窗
if (result !== undefined) {
close();
}
} catch (error) {
console.error('确认操作失败:', error);
// 发生错误时不关闭弹窗,让用户重试
} finally {
loading.value = false;
}
};
// 取消按钮点击处理
const handleNegativeClick = async () => {
try {
const result = await negativeEmitter();
// 只有当返回值不为undefined时才关闭弹窗
if (result !== undefined) {
close();
}
} catch (error) {
console.error('取消操作失败:', error);
// 即使取消操作失败,通常也应该关闭弹窗
close();
}
};
</script>使用示例
// 表单验证场景
const result = await modal({
title: '保存表单',
content: '确定要保存当前表单吗?',
positive: async () => {
// 验证表单
const isValid = validateForm();
if (!isValid) {
showMessage('表单验证失败,请检查输入');
return; // 返回undefined,弹窗保持打开
}
// 提交表单
try {
await submitForm();
showMessage('保存成功');
return true; // 返回值,弹窗关闭
} catch (error) {
showMessage('保存失败,请重试');
return; // 返回undefined,弹窗保持打开
}
},
negative: () => {
return false; // 直接关闭弹窗
}
});
// 删除确认场景 - 使用confirm
const deleteResult = await confirm(
`确定要删除 "${fileName}" 吗?此操作不可撤销。`,
'删除确认'
);
// confirm返回boolean值:true表示确认,false表示取消
if (deleteResult.promise) {
const userConfirmed = await deleteResult.promise;
if (userConfirmed) {
try {
await deleteFile(fileId);
showMessage('文件删除成功');
} catch (error) {
showMessage('删除失败:' + error.message);
}
}
}
// 复杂异步操作场景 - 使用modal
const complexResult = await modal({
title: '批量处理',
content: BatchProcessComponent,
props: { fileList },
popupOptions: {
positive: true,
negative: true
}
});
// 在BatchProcessComponent中使用setPositive/setNegative
// 可以返回复杂的处理结果最佳实践
- 适配器配置:在应用启动时配置所需的适配器组件
- 内存管理:使用
closeAll()在路由切换时清理弹窗 - 错误处理:为异步操作添加适当的错误处理
- 类型安全:充分利用 TypeScript 类型定义
- 性能优化:利用组件缓存机制,避免频繁创建销毁
- 管理器使用:推荐使用
getPopupManager()获取全局管理器实例 - Emitter使用:正确处理 emitter 的返回值,提供良好的用户体验
许可证
MIT License
