原理

全局存在一个弹窗管理器,他管理着一个数组,所有的弹窗触发全部包成一个函数,交给管理器,管理器去查看队列是否有内容,如果有内容就不触发,无内容就将本次函数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
分类: vue 项目实战 标签: 管理器弹窗弹窗队列

评论

暂无评论数据

暂无评论数据

目录