mini-dlpu-v3/miniprogram/modular/PopupLayer.ts

309 lines
6.9 KiB
TypeScript

import { IAnyData } from "core/Api";
import { Emitter } from "core/Emitter";
import { Modular, Manager } from "../core/Module";
/**
* 动画类型
*/
enum AnimateType {
fade = 1,
scale = 2,
none = 3,
}
/**
* 显示层
*/
class DisplayLayer {
/**
* 类名
*/
public get className(): string {
let res = this.isDisplay ? "block" : "none";
switch (this.animateType) {
case AnimateType.fade:
res += " mask";
break;
case AnimateType.scale:
res += " layer";
break;
case AnimateType.none:
res += " occlude";
break;
}
switch (this.animateType) {
case AnimateType.fade:
res += this.isShow ? " show-fade" : " hide-fade";
break;
case AnimateType.scale:
res += this.isShow ? " show-scale" : " hide-scale";
break;
case AnimateType.none:
break;
}
return res;
}
/**
* Layer 使用的 key
*/
public key: string = "";
/**
* 使用的动画类型
*/
public animateType: AnimateType = AnimateType.scale;
/**
* 动画时间
*/
public get animateTime(): number {
switch (this.animateType) {
case AnimateType.fade:
return 100;
case AnimateType.scale:
return 300;
case AnimateType.none:
return -1;
}
};
/**
* 是否显示
*/
public isDisplay: boolean = false;
/**
* 是否显示
*/
public isShow: boolean = false;
/**
* 消失动画计时器
*/
public disappearTimer?: number;
}
/**
* 弹出层事件
*/
type IPopupLayerEvent<L extends string> = {
/**
* 点击蒙版时
*/
clickMask: void
/**
* 显示层
*/
show: L;
/**
* 隐藏层
*/
hide: L;
/**
* 层状态改变
*/
change: Readonly<DisplayLayer>;
}
type commonLayerType = "mask" | "occlude";
/**
* 弹出层
*/
class PopupLayer<
L extends string,
M extends Manager = Manager
> extends Modular<M, {}, IPopupLayerEvent<L | commonLayerType>> {
/**
* 当点击时是否自动关闭蒙版
*/
public autoCloseOnClick: boolean = true;
/**
* 关闭动画执行时是否屏蔽用户点击
*/
public showOccludeWhenHide: boolean = true;
/**
* 显示 Layer 时自动关闭其他层
*/
public hideOtherWhenShow: boolean = true;
/**
* 层列表
*/
private layers: Map<L | commonLayerType, DisplayLayer> = new Map();
/**
* 初始化层
* @param key 初始化关键字
*/
public initLayers(key: L[]) {
for (let i = 0; i < key.length; i++) {
this.render(this.getDisplayLayer(key[i]));
}
}
public onLoad(): void {
this.on("show", this.handleShowLayer);
this.on("hide", this.handleHideLayer);
this.setFunc(this.handleClickMask, "clickMask");
// 添加蒙版层
const maskLayer = this.getDisplayLayer("mask");
maskLayer.animateType = AnimateType.fade;
this.render(maskLayer);
// 添加遮蔽层
const occludeLayer = this.getDisplayLayer("occlude");
occludeLayer.animateType = AnimateType.none;
this.render(occludeLayer);
}
/**
* 渲染 Layers
*/
private render(layer: DisplayLayer) {
this.setData({ [`${ layer.key }$className`]: layer.className });
}
/**
* 获取显示层
*/
private getDisplayLayer<K extends L | commonLayerType>(e: K): DisplayLayer {
let displayLayer = this.layers.get(e);
if (!displayLayer) {
displayLayer = new DisplayLayer();
displayLayer.key = e;
this.layers.set(e, displayLayer);
}
return displayLayer;
}
/**
* 响应蒙版点击事件
*/
private handleClickMask = () => {
if (!this.autoCloseOnClick) return;
// 关闭全部开启的层
this.layers.forEach((layer) => {
if (layer.isShow) (this as Emitter<IAnyData>).emit("hide", layer.key);
});
// 关闭蒙版
(this as Emitter<IAnyData>).emit("hide", "mask");
}
/**
* 响应显示层事件
*/
private handleShowLayer = <K extends L | commonLayerType>(e: K) => {
let displayLayer = this.getDisplayLayer(e);
// 阻止未发生的变化
if (displayLayer.isShow) return;
// 关闭其他层
if (e !== "mask" && e !== "occlude" && this.hideOtherWhenShow) {
this.layers.forEach((layer) => {
if (layer.key === "mask" || layer.key === "occlude") return;
if (layer.isShow) {
(this as Emitter<IAnyData>).emit("hide", layer.key);
}
});
}
// 显示蒙版
if (e !== "mask" && e !== "occlude")
(this as Emitter<IAnyData>).emit("show", "mask");
// 取消消失定时
displayLayer.disappearTimer &&
clearTimeout(displayLayer.disappearTimer);
displayLayer.isShow = true;
displayLayer.isDisplay = true;
this.render(displayLayer);
this.emit("change", displayLayer);
};
/**
* 响应隐藏层事件
*/
private handleHideLayer = <K extends L | commonLayerType>(e: K) => {
let displayLayer = this.getDisplayLayer(e);
// 阻止未发生的变化
if (!displayLayer.isShow) return;
if (displayLayer.animateTime <= 0) {
displayLayer.isShow = false;
displayLayer.isDisplay = false;
this.render(displayLayer);
} else {
displayLayer.isShow = false;
this.render(displayLayer);
// 开启遮蔽
if (this.showOccludeWhenHide) {
(this as Emitter<IAnyData>).emit("show", "occlude");
}
displayLayer.disappearTimer = setTimeout(() => {
displayLayer.isDisplay = false;
this.render(displayLayer);
// 取消 timer
displayLayer.disappearTimer = undefined;
// 检测是否关闭遮蔽
let needOcclude = true;
this.layers.forEach((layer) => {
if (layer === displayLayer) return;
if (layer.disappearTimer) needOcclude = false;
});
// 关闭遮蔽
if (needOcclude && this.showOccludeWhenHide) {
(this as Emitter<IAnyData>).emit("hide", "occlude");
}
}, displayLayer.animateTime);
}
// 关闭蒙版
if (e !== "mask" && e !== "occlude") {
let needMask = true;
this.layers.forEach((layer) => {
if (layer === displayLayer) return;
if (layer.isShow) needMask = false;
});
if (needMask) (this as Emitter<IAnyData>).emit("hide", "mask");
}
this.emit("change", displayLayer);
}
}
export { PopupLayer };
export default PopupLayer;