Skip to content

全局弹框 · 基础篇 ​

概述 ​

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
  1. 在 state.instances 中找到 mark 匹配的实例
  2. 设置 show = false(触发 UI 关闭动画)
  3. 260ms 后 splice 移除 + dropStaticJsRender(mark) 清理资源

closeAll() —— 关闭全部弹框 ​

typescript
closeAll(): void

直接将 state.instances = [],不逐一执行清理逻辑。适用于"全部重置"场景。


资源清理对比 ​

方法清理动作延迟适用场景
open().closeremove(mark) → dropStaticJsRender260ms✅ 推荐:单个弹框关闭
expose.close()pop() + removeStaticRender0ms简单关闭顶层
expose.remove(k)splice() + dropStaticJsRender260ms关闭任意指定弹框
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 被调用

下一步 ​