全局弹框 · 基础篇
概述
Jiess Plus 的弹框系统基于 BuildDialog 构建器,提供无限级弹框栈管理。弹框实例保存在 state.instances 数组中,支持打开、关闭、移除、全部关闭等操作。
框架特化文档: AntDesign | ElementPlus | Vant
$JiessDialog() —— 创建弹框配置
javascript
import { $JiessDialog } from '@jiess/plus/vue3';
const dialogConfig = $JiessDialog({
$title: '弹框标题',
$content: {
// 弹框内容区域配置
},
$footer: {
// 底部按钮区域配置
},
width: 600, // 透传给 UI 组件的属性
onCancel: () => {}, // 取消回调
});BuildDialog 源码架构
BuildDialog
├── setup()
│ ├── $reactive({ instances: [] }) ← 弹框实例栈
│ ├── expose.open({ mark, ...rest }) ← 打开弹框 → push 到栈
│ ├── expose.close() ← 关闭顶层弹框 → pop + removeStaticRender
│ ├── expose.remove(mark) ← 关闭指定弹框 → splice + dropStaticJsRender (260ms延迟)
│ ├── expose.closeAll() ← 关闭全部 → state.instances = []
│ └── jiess.$tan(param) ← 从 Jiess 上下文快捷调用 open()
└── children: { $proxy: state, field: 'instances', done(arr) }核心 API
open(params) —— 打开弹框
typescript
open(params: {
mark?: string; // 弹框唯一标识(不传则自动生成:Date.now()_随机数)
width?: number; // 弹框宽度(默认 960)
...restParam; // 其他参数透传
}): {
mark: string; // 弹框标识
close: Function; // 关闭函数(调用 remove())
context: Context; // Jiess 上下文
expose: Object; // 弹框管理器暴露对象
...initCustomExpose; // 自定义暴露属性
}javascript
// 示例:打开弹框并获取引用
const { mark, close } = this.jiess.$tan({
$title: '编辑用户',
$content: { /* 表单 */ },
});
// 稍后通过 close() 关闭
close();close() —— 关闭最顶层弹框
typescript
close(): void从 state.instances 中 pop() 移除最后打开的弹框,并调用 removeStaticRender(key) 清理静态渲染。
⚠️
close()不调用dropStaticJsRender,清理不完整。推荐使用open()返回值的close。
remove(mark) —— 关闭指定弹框
typescript
remove(mark: string): void- 在
state.instances中找到mark匹配的实例 - 设置
show = false(触发 UI 关闭动画) - 260ms 后
splice移除 +dropStaticJsRender(mark)清理资源
closeAll() —— 关闭全部弹框
typescript
closeAll(): void直接将 state.instances = [],不逐一执行清理逻辑。适用于"全部重置"场景。
资源清理对比
| 方法 | 清理动作 | 延迟 | 适用场景 |
|---|---|---|---|
open().close | remove(mark) → dropStaticJsRender | 260ms | ✅ 推荐:单个弹框关闭 |
expose.close() | pop() + removeStaticRender | 0ms | 简单关闭顶层 |
expose.remove(k) | splice() + dropStaticJsRender | 260ms | 关闭任意指定弹框 |
expose.closeAll() | state.instances = [] | 0ms | 全部重置(不清理资源) |
使用示例
示例 1:基础弹框
javascript
import { $JiessDialog, $Input, $Button } from '@jiess/plus/vue3';
const dialogConfig = $JiessDialog({
$title: '添加用户',
$content: {
children: {
name: { $label: '姓名', $Input: {} },
email: { $label: '邮箱', $Input: {} },
},
},
$footer: {
$Btns: {
children: [
{
$Button: {
children: '取消',
onClick: 'cancel',
},
},
{
$Button: {
children: '确定',
type: 'primary',
onClick: 'submit',
},
},
],
},
},
width: 520,
});示例 2:嵌套弹框
javascript
const outerDialog = $JiessDialog({
$title: '第一层',
$content: {
children: {
text: '点击按钮打开第二层弹框',
$Button: {
children: '打开子弹框',
type: 'primary',
onClick() {
this.jiess.$tan({
$title: '第二层',
$content: { children: { text: '这是嵌套弹框' } },
});
},
},
},
},
$footer: {
$Btns: {
children: [{
$Button: { children: '关闭全部', onClick: 'closeAll' },
}],
},
},
});示例 3:通过页面的 jiess 入口打开弹框
javascript
// 在任何 Vue 组件的 setup() 中
const handleOpenDialog = () => {
const { mark, close, expose } = jiess.$tan({
$title: '用户详情',
$content: {
children: {
$JiessTable: {
action: `http://api.example.com/users/${userId}`,
$fields: [
{ $label: '姓名', $name: 'name' },
{ $label: '邮箱', $name: 'email' },
],
},
},
},
width: 800,
});
};进阶场景
场景1:弹框间通信(父弹框 → 子弹框)
javascript
// 父弹框打开子弹框,并传递数据/回调
const parentDialog = $JiessDialog({
$title: '选择用户',
$content: {
$JiessTable: {
rowKey: 'id',
action: '/api/users',
$fields: [
{ $label: '姓名', $name: 'name' },
{ $label: '邮箱', $name: 'email' },
],
// 点击行 → 打开子弹框
@rowClick: (row) => {
this.jiess.$tan({
$title: `用户详情 - ${row.name}`,
$content: {
children: {
name: { $label: '姓名', $Input: { $value: row.name } },
email: { $label: '邮箱', $Input: { $value: row.email } },
phone: { $label: '手机', $Input: { $value: row.phone } },
},
},
$footer: {
$Btns: {
children: [{
$Button: {
children: '选择此用户',
type: 'primary',
onClick() {
// 将数据传回父页面
selectedUser.value = row;
// 关闭子弹框
this.$parent?.close();
},
},
}],
},
},
});
},
},
},
});场景2:多弹框管理(确认弹框 + 编辑弹框)
javascript
// 典型场景:列表操作列中,先弹出确认框,确认后再弹出编辑框
const handleEditWithConfirm = async (row) => {
// 步骤1:弹出确认弹框
const confirmDialog = jiess.$tan({
$title: '提示',
$content: {
children: {
text: `正在编辑 "${row.name}",确定要进入编辑吗?`,
},
},
$footer: {
$Btns: {
children: [
{
$Button: {
children: '取消',
onClick: 'cancel',
},
},
{
$Button: {
children: '确定',
type: 'primary',
onClick() {
// 步骤2:关闭确认弹框
confirmDialog.close();
// 步骤3:打开编辑弹框
jiess.$tan({
$title: `编辑 - ${row.name}`,
$content: {
$Form: {
children: {
name: { $Input: { $label: '姓名', $value: row.name } },
email: { $Input: { $label: '邮箱', $value: row.email } },
},
},
},
$footer: {
$Btns: {
children: [
{
$Button: {
children: '保存',
type: 'primary',
onClick() {
// 保存逻辑...
this.$parent?.close();
},
},
},
],
},
},
});
},
},
},
],
},
},
});
};场景3:一次性弹出多个弹框的层级管理
javascript
// 当需要同时打开多个弹框时,注意层级管理:
// 1. 确认优先级弹框(confirm/dialog)
// 2. 编辑类弹框(form)
// 3. 查看类弹框(detail)
// 不利于用户体验的做法:
// ❌ 同时打开多个非模态弹框,用户不知道哪个是主要的
// ❌ 在 loading 弹框未关闭时就打开新弹框
// 推荐做法:
const handleOperation = async (row) => {
// 先关闭当前所有弹框
this.jiess.expose.closeAll();
// 再逐个打开
const detailDialog = this.jiess.$tan({
$title: '详情',
$content: { /* ... */ },
});
// 如果需要在详情之上再弹确认框
const confirmDialog = this.jiess.$tan({
$title: '确认操作',
$content: { children: { text: '确定要执行此操作吗?' } },
width: 420,
$footer: {
$Btns: {
children: [
{
$Button: {
children: '取消',
onClick() {
confirmDialog.close();
},
},
},
{
$Button: {
children: '确定',
type: 'primary',
onClick() {
confirmDialog.close();
detailDialog.close();
// 执行实际操作
},
},
},
],
},
},
});
};注意事项
| 事项 | 说明 |
|---|---|
| 默认宽度 | 960px,可通过 open() 参数或 injectParam 覆盖 |
| mark 不传 | 自动生成 Date.now()_随机数,确保唯一性 |
| 动画延迟 | remove() 有 260ms 延迟(等待 vant 动画),ElementPlus/React 同理 |
| Vant 特殊处理 | Vant 中 show 是组合式响应对象,remove() 通过 hasProxy 判断处理方式 |
| 资源清理 | 推荐使用 open().close 而非 expose.close() 以确保 dropStaticJsRender 被调用 |
下一步
- 框架特化文档: ElementPlus 弹框 | Vant 弹框 | AntDesign 弹框
- 快捷表单-基础.md —— 弹框内嵌表单校验