一个页面只能出现一个弹窗
如何解决弹窗优先级
● 手动唤起弹窗,有明确指向,此时直接去关闭上一个弹窗,唤起当前弹窗;
● 自动唤起弹窗:
○ 首先设置优先级,(可能存在多个同类型的,比如多个携带参数唤起的);
○ 如果命中参数则直接将当前的弹窗标识设置为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');
},