ant-design-vue 同时弹多弹窗

本篇简单实现antdv同时弹多个弹窗

起因

今天听到产品给同事提了个需求,有个表格原本加了行事件,点击该行会打开一个弹窗,之前只能同时打开一个弹窗,现在需要同时打开多个。

分析

这个弹窗挺复杂的,之前专门有个弹窗的组件绑定在模版跟路径下,通过点击行来切换这个弹窗的显隐。
本来没啥大问题,但是现在要同时弹多个弹窗的话就不够用了,因为dom只有一个。

思路

  1. 使用动态弹窗。
    antdv官网提供了API,可以使用Modal.info / Modal.success / Modal.error / Modal.warning / Modal.confirm几个方法来快速创建弹窗。

伪代码如下:

1
2
3
4
5
6
7
8
9
const OpenModal = (key: string) => {
Modal.confirm({
content: createVNode(createVNode('div', { class: 'content' }, key)),
title: 'Modal',
onOk() {},
onCancel() {
},
});
};

看起来很简单,但是测试时却出现了问题,因为Modal组件自带遮罩,第一个弹窗出现后,因为遮罩阻挡,第二个点击事件无法触发。

  1. 去掉遮罩
    根据Modal组件文档,可以传入mask属性来移除遮罩,但实际操作时发现,除了遮罩层,还有一个dialog的节点占满了屏幕,也会阻挡第二次点击事件。还好组件文档也相应提供了一个wrapClassName属性,我们可以通过自定义类名来自定义这个节点。

伪代码如下:

1
2
3
4
5
6
7
8
9
10
const OpenModal = (key: string) => {
Modal.confirm({
mask: false,
wrapClassName: `test-modal`,
content: createVNode(createVNode('div', { class: 'content' }, key)),
title: 'Modal',
onOk() {},
onCancel() {},
});
};
1
2
3
4
5
6
7
8
9
10
11
.test-modal {
width: fit-content;
height: fit-content;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
top: 30%;
left: 30%;

.ant-modal {
top: 0;
}
}

其实到这本篇就算结束了,但是多次出发点击事件的时候,多个弹窗整整齐齐堆在一起,要不是有打开动画,还以为只开了一个弹窗呢。

  1. 增加位置偏移
    提供一个简单的实现,上文中已经给弹窗增加了topleft属性,我们假设每打开一个新弹窗,相对前一个弹窗向右/向下各便宜40px

伪代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let num = 0;

const OpenModal = (key: string) => {
Modal.confirm({
mask: false,
wrapClassName: `test-modal test-modal-${num}`,
content: h(h('div', { class: 'content' }, key)),
title: 'Modal',
onOk() {},
onCancel() {
num--;
},
});
num++;
};

注意

这里的num变量是特意不使用响应式变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.test-modal {
width: fit-content;
height: fit-content;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
top: 30%;
left: 30%;

.ant-modal {
top: 0;
}
}

@iterations: 5; // 定义循环次数
.generate-classes(@i) when (@i <= @iterations) {
.test-modal-@{i} {
// transform-origin: calc(40px * @i) calc(40px * @i);
top: calc(30% + (40px * @i));
left: calc(30% + (40px * @i));
}
.generate-classes(@i + 1);
}
.generate-classes(0); // 启动循环

最终效果

后话

当然,到这一步需求还没完,还缺一个手动拖拽,这个比较麻烦,有空再写。