弹窗队列管理器
原理
全局存在一个弹窗管理器,他管理着一个数组,所有的弹窗触发全部包成一个函数,交给管理器,管理器去查看队列是否有内容,如果有内容就不触发,无内容就将本次函数push进数组中,然后触发next方法弹出下一个弹窗。
当弹窗关闭后,触发管理器的remove方法,数组首位出栈,触发next方法,弹出下一个弹窗
示意图
源码
四个文件:
- dialogMap.ts 弹窗数据,可能这个弹窗这次需要队列,下次就不需要,通过这个配置
- index.ts 入口文件
- queueManager.ts 管理器
- types.ts 类型声明
types.ts
/*
* @Author: mulingyuer
* @Date: 2022-04-06 15:25:17
* @LastEditTime: 2022-04-06 15:26:37
* @LastEditors: mulingyuer
* @Description: 队列管理器类型声明
* @FilePath: \casino-xian\src\utils\dialogQueueManager\types.ts
* 怎么可能会有bug!!!
*/
export interface QueueItem {
name: string;
open: Function;
}
export type QueueArr = Array<QueueItem>;
dialogMap.ts
/*
* @Author: mulingyuer
* @Date: 2022-04-06 14:38:08
* @LastEditTime: 2022-04-06 14:58:10
* @LastEditors: mulingyuer
* @Description:弹窗类型
* @FilePath: \casino-xian\src\utils\dialogQueueManager\dialogMap.ts
* 怎么可能会有bug!!!
*/
const dialogMap = {
REDPACKETDIALOG: {
name: "红包弹窗",
global: true, //全局唯一
},
};
export default dialogMap;
index.ts
/*
* @Author: mulingyuer
* @Date: 2022-04-06 13:56:39
* @LastEditTime: 2022-04-06 14:12:26
* @LastEditors: mulingyuer
* @Description: 弹窗队列管理器
* @FilePath: \casino-xian\src\utils\dialogQueueManager\index.ts
* 怎么可能会有bug!!!
*/
import QueueManager from "./queueManager";
const queueManager = QueueManager.getInstance();
export default queueManager;
queueManager.ts
/*
* @Author: mulingyuer
* @Date: 2022-04-06 13:56:59
* @LastEditTime: 2022-04-08 16:49:59
* @LastEditors: mulingyuer
* @Description: 队列管理器
* @FilePath: \casino-xian\src\utils\dialogQueueManager\queueManager.ts
* 怎么可能会有bug!!!
*/
import { QueueArr } from "./types";
import dialogMap from "./dialogMap";
class QueueManager {
private static _instance: QueueManager;
private queueArr: QueueArr = [];
// eslint-disable-next-line
private constructor() {}
/**
* @description: 获取实例
* @param {*}
* @Date: 2022-04-06 13:58:36
* @Author: mulingyuer
*/
static getInstance() {
if (!QueueManager._instance) {
QueueManager._instance = new QueueManager();
}
return QueueManager._instance;
}
//入栈
public add(name: string, fn: Function) {
if (this.isGlobal(name)) {
//全局唯一弹窗
this.queueArr.push({ name, open: fn });
this.showNext();
} else {
try {
fn();
} catch (error) {
console.error("弹窗不合法,单独开启失败", error);
}
}
}
//出栈
public remove(name?: string) {
if (name && name.trim() !== "") {
const findIndex = this.queueArr.findIndex((item) => item.name === name);
if (findIndex > -1) {
this.queueArr.splice(findIndex, 1);
this.showNext();
}
} else {
this.queueArr.shift();
this.showNext();
}
}
//获取队列长度
public getQueueLength() {
return this.queueArr.length;
}
/**
* @description: 插队
* @param {number} index 插队位置,数组下标
* @Date: 2022-04-08 11:12:08
* @Author: mulingyuer
*/
public jumpQueue(index: number, name: string, fn: Function) {
if (!this.isGlobal(name)) fn();
if (this.isEmpty()) {
this.add(name, fn);
} else {
const length = this.queueArr.length;
switch (index) {
case 0:
this.queueArr.splice(1, 0, { name, open: fn });
break;
default: {
let spliceIndex = index;
if (index > length) {
spliceIndex = length;
}
this.queueArr.splice(spliceIndex, 0, { name, open: fn });
}
}
this.showNext();
}
}
//弹出下一个弹窗
private showNext() {
if (this.isEmpty()) return;
try {
this.queueArr[0].open();
} catch (error) {
console.error("开启弹窗失败", this.queueArr[0].name, error);
}
}
//是否为空队列
private isEmpty(): boolean {
return this.queueArr.length === 0;
}
//清空队列
private clear() {
this.queueArr = [];
}
//根据name判断是否全局唯一
private isGlobal(name: string): boolean {
let flag = false;
if (name && name.trim() !== "" && dialogMap[name]) {
const { global } = dialogMap[name];
flag = global;
}
return flag;
}
}
export default QueueManager;
用法
import QueueManager from "@/utils/dialogQueueManager";
function openDialog() {
QueueManager.add(
"REDPACKETDIALOG",
() => {
store.commit(`page/${Mutation["SET_SHOWREDPACKETDIALOG"]}`, true);
}
);
}
function closeDialog() {
QueueManager.remove("REDPACKETDIALOG");
}
使用上的一些注意点:
- rmove虽然可以触发多次,但是如果add了两次相同name的弹窗,可能会导致后面未触发的弹窗也从队列中移除了。
- name与map中的要一一对应,如果不存在,会被视为非队列弹窗,直接运行函数了
- remove删除一定要传name,否则视为无效remove
版权申明
本文系作者 @木灵鱼儿 原创发布在木灵鱼儿站点。未经许可,禁止转载。
暂无评论数据