弹窗管理工具

一个页面只能出现一个弹窗

如何解决弹窗优先级

● 手动唤起弹窗,有明确指向,此时直接去关闭上一个弹窗,唤起当前弹窗;
● 自动唤起弹窗:
○ 首先设置优先级,(可能存在多个同类型的,比如多个携带参数唤起的);
○ 如果命中参数则直接将当前的弹窗标识设置为true,设置等待被唤起弹窗的标识;后续遇到其他弹窗假设其他弹窗的优先级低于当前等待被唤起的弹窗,直接不管,不去走唤起弹窗。如果优先级高于等待唤起的弹窗则更新等待唤起的弹窗为当前项,一直到所有弹窗都经过处理,将等待被唤起的弹窗唤起。

如何解决时机问题?统一去请求?

● 当前项目可能存在很久的代码,弹窗的统一管理可能需要调整很多代码,且某些弹窗需要经过很多前置的rpc才能去判断是否展示,这样的话,页面可能首先需要关注弹窗。
● 是否可以在原有代码的逻辑去控制?

实现方案

interface IPopUp {
  key: string;
  order: number;
  [key: string]: any;
}

interface IPopupMap {
  [key: string]: {
    loaded: boolean;
    _loaded: boolean;
    key: string;
    order: number;
  };
}

export function PopUpManagementTool(popupList: IPopUp[], timeout = 50000) {
  let popupMap: IPopupMap = {};
  const popupPromise = {};
  // 等待显示的弹窗key
  let waitingForShowPopUpKey = null;
  let timeouted = false;
  let timer = null;

  popupList.forEach((popup) => {
    popupMap[popup.key] = {
      ...popup,
      loaded: false,
      _loaded: false,
    };
  });

  const reslovePopUpPromise = () => {
    Object.keys(popupPromise).forEach((key) => {
      popupPromise[key] && popupPromise[key](key === waitingForShowPopUpKey);
    });
  };

  const handleTimeout = (time: number) => {
    timer = setTimeout(() => {
      timer && clearTimeout(timer);
      // 没有加载完才去做超时的一个处理
      if (!isCompleteLoaded()) {
        reslovePopUpPromise();
        timeouted = true;
      }
    }, time);
  };

  // 判断是否已经完全加载完成
  const isCompleteLoaded = () => {
    return !(Object.values(popupMap).findIndex((item) => !item._loaded) > -1);
  };

  // 如果有优先级高的已经加载过了,那就说明这个不需要被加载
  const getNeedLoadByKey = (key: string) => {
    return !popupMap[key]._loaded;
  };

  // 全部加载完成的时候需要去resolve
  const hanldePromise = () => {
    if (isCompleteLoaded()) {
      reslovePopUpPromise();
    }
  };

  // 更新优先级小的
  const updateLoaded = (order: number) => {
    Object.keys(popupMap).forEach((key) => {
      if (popupMap[key].order <= order) {
        popupMap[key]._loaded = true;
      }
    });
  };

  // 请求完成之后更新弹窗状态
  const updateLoadedByKey = (key: string, isSuccess: boolean) => {
    const curPopup = popupMap[key];
    if (!curPopup) return Promise.resolve(false);
    curPopup._loaded = true;
    curPopup.loaded = isSuccess;
    // 只有存在了第一个需要展示的弹窗才有超时的一个意义
    if (isSuccess && !timer) {
      // 初始化超时处理
      handleTimeout(timeout);
    }
    // 超时不管
    if (timeouted) return Promise.resolve(false);
    if (isSuccess) {
      updateLoaded(curPopup.order);
      if (
        !waitingForShowPopUpKey ||
        popupMap[waitingForShowPopUpKey].order < popupMap[key].order
      ) {
        waitingForShowPopUpKey = key;
      }
    }
    // 需要先完成下面的return才能去处理,所以使用微任务处理
    Promise.resolve().then(() => {
      hanldePromise();
    });
    return new Promise((reslove) => {
      isSuccess ? (popupPromise[key] = reslove) : reslove(false);
    });
  };

  const clearAllPopUps = () => {
    popupMap = {};
  };

  const getPopupisRelLoadedByKey = (key: string) => {
    return popupMap[key].loaded;
  };

  const resetTimeouted = () => {
    timeouted = false;
  };

  // 特定的一个弹窗出现才去超时可以使用
  const resetTimeout = (time: number = timeout) => {
    handleTimeout(time);
    resetTimeouted();
  };

  return {
    getPopupisRelLoadedByKey,
    updateLoadedByKey,
    clearAllPopUps,
    getNeedLoadByKey,
    resetTimeouted,
    resetTimeout,
  };
}

使用

  async onLoad() {
    await this.handlePopupC();
    this.handlePopupA();
    this.handlePopupB();
  },
  async handlePopupA() {
    if (!popupTool.getNeedLoadByKey('A')) return;
    try {
      const res = await createPopInofo('A');
      this.setData({
        popupA: res,
      });
      popupTool.updateLoadedByKey('A', true).then((show: boolean) => {
        this.setData({
          visibleA: show,
        });
      });
    } catch (error) {
      popupTool.updateLoadedByKey('A', false);
      this.setData({
        popupA: {},
      });
    }
    console.log('============>A');
  },
  async handlePopupB() {
    if (!popupTool.getNeedLoadByKey('B')) return;
    try {
      const res = await createPopInofo('B');
      this.setData({
        popupB: res,
      });
      popupTool.updateLoadedByKey('B', true).then((show: boolean) => {
        this.setData({
          visibleB: show,
        });
      });
    } catch (error) {
      popupTool.updateLoadedByKey('B', false);
      this.setData({
        popupB: {},
      });
    }
    console.log('============>B');
  },
  async handlePopupC() {
    if (!popupTool.getNeedLoadByKey('C')) return;
    try {
      const res = await createPopInofo('C');
      this.setData({
        popupC: res,
      });
      popupTool.updateLoadedByKey('C', true).then((show: boolean) => {
        this.setData({
          visibleC: show,
        });
      });
    } catch (error) {
      popupTool.updateLoadedByKey('C', false);
      this.setData({
        popupC: {},
      });
    }
    console.log('============>C');
  },
  • 8
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值