From 943798f53c8f9894bc21735de470bb97d0150221 Mon Sep 17 00:00:00 2001 From: mrkbear Date: Sun, 23 Jan 2022 20:34:52 +0800 Subject: [PATCH 1/2] (#36) Add popuplayer. --- miniprogram/modular/PopupLayer.scss | 0 miniprogram/modular/PopupLayer.ts | 130 +++++++++++++++++++++++++++ miniprogram/pages/Account/Account.ts | 5 +- 3 files changed, 133 insertions(+), 2 deletions(-) create mode 100644 miniprogram/modular/PopupLayer.scss create mode 100644 miniprogram/modular/PopupLayer.ts diff --git a/miniprogram/modular/PopupLayer.scss b/miniprogram/modular/PopupLayer.scss new file mode 100644 index 0000000..e69de29 diff --git a/miniprogram/modular/PopupLayer.ts b/miniprogram/modular/PopupLayer.ts new file mode 100644 index 0000000..dfb37c5 --- /dev/null +++ b/miniprogram/modular/PopupLayer.ts @@ -0,0 +1,130 @@ +import { Modular, Manager } from "../core/Module"; + +/** + * 显示层 + */ +class DisplayLayer { + + /** + * Layer 使用的 key + */ + public key: string = ""; + + /** + * 使用的动画类型 + */ + public animateTime: number = 300; + + /** + * 蒙版是否显示 + */ + public isDisplay: boolean = false; + + /** + * 蒙版是否显示 + */ + public isShow: boolean = false; + + /** + * 消失动画计时器 + */ + public disappearTimer?: number; +} + +/** + * 弹出层事件 + */ +type IPopupLayerEvent = { + + /** + * 点击蒙版时 + */ + clickMask: void + + /** + * 显示层 + */ + show: L; + + /** + * 隐藏层 + */ + hide: L; + + /** + * 层状态改变 + */ + change: Readonly; +} + +/** + * 弹出层 + */ +class PopupLayer< + L extends string, + M extends Manager = Manager +> extends Modular> { + + /** + * 层列表 + */ + private layers: Map = new Map(); + + public onLoad(): void { + this.on("show", this.handleShowLayer); + this.on("hide", this.handleHideLayer); + } + + /** + * 获取显示层 + */ + private getDisplayLayer(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 handleShowLayer = (e: K) => { + let displayLayer = this.getDisplayLayer(e); + + // 取消消失定时 + displayLayer.disappearTimer && + clearTimeout(displayLayer.disappearTimer); + + this.setData({ + [`${ e }$isShow`]: true, + [`${ e }$isDisplay`]: true + }); + + this.emit("change", displayLayer); + }; + + /** + * 响应隐藏层事件 + */ + private handleHideLayer = (e: K) => { + let displayLayer = this.getDisplayLayer(e); + + this.setData({ + [`${ e }$isShow`]: false + }); + + displayLayer.disappearTimer = setTimeout(() => { + this.setData({ + [`${ e }$isDisplay`]: false + }); + }, displayLayer.animateTime); + + this.emit("change", displayLayer); + } +} + +export { PopupLayer }; +export default PopupLayer; \ No newline at end of file diff --git a/miniprogram/pages/Account/Account.ts b/miniprogram/pages/Account/Account.ts index 3751888..df02ab1 100644 --- a/miniprogram/pages/Account/Account.ts +++ b/miniprogram/pages/Account/Account.ts @@ -2,7 +2,7 @@ import { Manager } from "../../core/Module"; import { UserCard } from "./UserCard"; import { MainFunction } from "./MainFunction"; import { FunctionList } from "./FunctionList"; -import { Mask } from "../../modular/Mask/Mask"; +import { PopupLayer } from "../../modular/PopupLayer"; (async () => { @@ -10,7 +10,8 @@ import { Mask } from "../../modular/Mask/Mask"; const { manager, query } = await Manager.PageAsync(); // 添加蒙版 Modular - // const mask = manager.addModule(Mask, "mask"); + const popupLayer: PopupLayer<"a" | "b"> = manager.addModule(PopupLayer, "mask") as any; + popupLayer.emit("show", "a"); // 添加 UserCard Modular manager.addModule(UserCard, "userCard"); From 18381aa0c4e382d70b4c7740d9bb67ccb57218a6 Mon Sep 17 00:00:00 2001 From: MrKBear Date: Mon, 24 Jan 2022 14:58:33 +0800 Subject: [PATCH 2/2] (#36) Merge mask modular & popup modular in popup layer modular. --- miniprogram/app.scss | 8 +- miniprogram/modular/Mask/Mask.scss | 45 -------- miniprogram/modular/Mask/Mask.ts | 115 -------------------- miniprogram/modular/PopupLayer.scss | 99 +++++++++++++++++ miniprogram/modular/PopupLayer.ts | 135 +++++++++++++++++++++--- miniprogram/pages/Account/Account.scss | 2 +- miniprogram/pages/Account/Account.ts | 19 +++- miniprogram/pages/Account/Account.wxml | 16 ++- miniprogram/pages/Account/TestLayerA.ts | 26 +++++ miniprogram/pages/Account/UserCard.ts | 10 +- 10 files changed, 286 insertions(+), 189 deletions(-) delete mode 100644 miniprogram/modular/Mask/Mask.scss delete mode 100644 miniprogram/modular/Mask/Mask.ts create mode 100644 miniprogram/pages/Account/TestLayerA.ts diff --git a/miniprogram/app.scss b/miniprogram/app.scss index d6fb045..ae0fd63 100644 --- a/miniprogram/app.scss +++ b/miniprogram/app.scss @@ -16,12 +16,16 @@ $black-filter: brightness(0) opacity(.65); $white-filter: brightness(100) opacity(.65); $blue-filter: opacity(1); -// 页面容器外边距 -view.container { +@mixin container { width: 88%; padding: 0 6%; } +// 页面容器外边距 +view.container { + @include container; +} + // 带阴影的 card view.card { width: calc( 100% - 40px ); diff --git a/miniprogram/modular/Mask/Mask.scss b/miniprogram/modular/Mask/Mask.scss deleted file mode 100644 index 326c031..0000000 --- a/miniprogram/modular/Mask/Mask.scss +++ /dev/null @@ -1,45 +0,0 @@ -@import "../../app.scss"; - -view.mask { - position: fixed; - width: 100%; - height: 100%; - background-color: rgba($color: #000000, $alpha: .2); - z-index: 1; -} - -view.mask.block { - display: block; -} - -view.mask.none { - display: none; -} - -view.mask.show { - animation: show .1s cubic-bezier(0, 0, 1, 1) both; - opacity: 1; -} - -view.mask.hide { - animation: hide .1s cubic-bezier(0, 0, 1, 1) both; - opacity: 0; -} - -@keyframes show{ - from { - opacity: 0; - } - to { - opacity: 1; - } -} - -@keyframes hide{ - from { - opacity: 1; - } - to { - opacity: 0; - } -} \ No newline at end of file diff --git a/miniprogram/modular/Mask/Mask.ts b/miniprogram/modular/Mask/Mask.ts deleted file mode 100644 index a873865..0000000 --- a/miniprogram/modular/Mask/Mask.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { Modular, Manager } from "../../core/Module"; - -/** - * 蒙版事件 - */ -type IMaskEvent = { - - /** - * 蒙版显示事件 - */ - show: void; - - /** - * 蒙版隐藏事件 - */ - hide: void; - - /** - * 蒙版状态改变事件 - */ - change: boolean; - - /** - * 蒙版点击事件 - */ - click: void; -} - -/** - * 蒙版 Modular - */ -class Mask extends Modular { - - /** - * 动画运行时间 - */ - public static readonly animateTime: number = 100; - - public data? = { - - /** - * 蒙版的层级 - */ - zIndex: 1, - - /** - * 蒙版是否显示 - */ - isDisplay: false, - - /** - * 蒙版是否显示 - */ - isShow: false - }; - - /** - * 当点击时是否自动关闭蒙版 - */ - public autoCloseOnClick: boolean = true; - - /** - * 消失动画计时器 - */ - private disappearTimer?: number; - - public override onLoad() { - this.setFunc(this.handleClickMask, "handleClickMask"); - this.on("show", this.showMask); - this.on("hide", this.hideMask); - } - - /** - * 显示蒙版 - */ - private showMask = () => { - - this.disappearTimer && clearTimeout(this.disappearTimer); - - this.setData({ - isShow: true, - isDisplay: true - }); - - this.emit("change", true); - } - - /** - * 隐藏蒙版 - */ - private hideMask = () => { - this.setData({ - isShow: false - }); - - this.disappearTimer = setTimeout(() => { - this.setData({ - isDisplay: false - }); - }, Mask.animateTime); - - this.emit("change", false); - } - - /** - * 处理蒙版点击事件 - */ - private handleClickMask() { - if (this.autoCloseOnClick) this.emit("hide"); - this.emit("click"); - } -} - -export { Mask }; -export default Mask; \ No newline at end of file diff --git a/miniprogram/modular/PopupLayer.scss b/miniprogram/modular/PopupLayer.scss index e69de29..38dbe26 100644 --- a/miniprogram/modular/PopupLayer.scss +++ b/miniprogram/modular/PopupLayer.scss @@ -0,0 +1,99 @@ +@import "../app.scss"; + +view.mask { + position: fixed; + width: 100%; + height: 100%; + background-color: rgba($color: #000000, $alpha: .2); + z-index: 1; +} + +view.layer { + position: fixed; + @include container; + height: 100%; + z-index: 2; + justify-content: center; + align-items: center; +} + +view.occlude { + position: fixed; + width: 100%; + height: 100%; + z-index: 3; +} + +view.mask.block, view.layer.block, view.occlude.block { + display: flex; +} + +view.mask.none, view.layer.none, view.occlude.none { + display: none; +} + +view.mask.show-fade, view.layer.show-fade, view.occlude.show-fade { + animation: show-fade .1s cubic-bezier(0, 0, 1, 1) both; + opacity: 1; +} + +view.mask.hide-fade, view.layer.hide-fade, view.occlude.hide-fade { + animation: hide-fade .1s cubic-bezier(0, 0, 1, 1) both; + opacity: 0; +} + +view.mask.show-scale, view.layer.show-scale, view.occlude.show-scale { + animation: show-scale .3s cubic-bezier(.1, .9, .2, 1) both, + show-fade .1s cubic-bezier(0, 0, 1, 1) both; + transform: scale3d(1, 1, 1); + opacity: 1; +} + +view.mask.hide-scale, view.layer.hide-scale, view.occlude.hide-scale { + animation: hide-scale .3s cubic-bezier(.1, .9, .2, 1) both, + hide-fade .1s cubic-bezier(0, 0, 1, 1) both; + transform: scale3d(.9, .9, 1); + opacity: 0; +} + +@media (prefers-color-scheme: dark) { + view.mask { + background-color: rgba($color: #000000, $alpha: .5); + } +} + +@keyframes show-fade{ + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +@keyframes hide-fade{ + from { + opacity: 1; + } + to { + opacity: 0; + } +} + +@keyframes show-scale{ + from { + transform: scale3d(1.15, 1.15, 1); + } + to { + transform: scale3d(1, 1, 1); + } +} + +@keyframes hide-scale{ + from { + transform: scale3d(1, 1, 1); + } + to { + transform: scale3d(.9, .9, 1); + } +} \ No newline at end of file diff --git a/miniprogram/modular/PopupLayer.ts b/miniprogram/modular/PopupLayer.ts index dfb37c5..4c11056 100644 --- a/miniprogram/modular/PopupLayer.ts +++ b/miniprogram/modular/PopupLayer.ts @@ -1,3 +1,5 @@ +import { IAnyData } from "core/Api"; +import { Emitter } from "core/Emitter"; import { Modular, Manager } from "../core/Module"; /** @@ -16,12 +18,12 @@ class DisplayLayer { public animateTime: number = 300; /** - * 蒙版是否显示 + * 是否显示 */ public isDisplay: boolean = false; /** - * 蒙版是否显示 + * 是否显示 */ public isShow: boolean = false; @@ -57,28 +59,54 @@ type IPopupLayerEvent = { change: Readonly; } +type commonLayerType = "mask" | "occlude"; + /** * 弹出层 */ class PopupLayer< L extends string, M extends Manager = Manager -> extends Modular> { +> extends Modular> { + + /** + * 当点击时是否自动关闭蒙版 + */ + public autoCloseOnClick: boolean = true; + + /** + * 关闭动画执行时是否屏蔽用户点击 + */ + public showOccludeWhenHide: boolean = true; + + /** + * 显示 Layer 时自动关闭其他层 + */ + public hideOtherWhenShow: boolean = true; /** * 层列表 */ - private layers: Map = new Map(); + private layers: Map = new Map(); public onLoad(): void { this.on("show", this.handleShowLayer); this.on("hide", this.handleHideLayer); + this.setFunc(this.handleClickMask, "clickMask"); + + // 添加蒙版层 + const maskLayer = this.getDisplayLayer("mask"); + maskLayer.animateTime = 100; + + // 添加遮蔽层 + const occludeLayer = this.getDisplayLayer("occlude"); + occludeLayer.animateTime = -1; } /** * 获取显示层 */ - private getDisplayLayer(e: K): DisplayLayer { + private getDisplayLayer(e: K): DisplayLayer { let displayLayer = this.layers.get(e); if (!displayLayer) { displayLayer = new DisplayLayer(); @@ -88,16 +116,51 @@ class PopupLayer< return displayLayer; } + /** + * 响应蒙版点击事件 + */ + private handleClickMask = () => { + + if (!this.autoCloseOnClick) return; + + // 关闭全部开启的层 + this.layers.forEach((layer) => { + if (layer.isShow) (this as Emitter).emit("hide", layer.key); + }); + + // 关闭蒙版 + (this as Emitter).emit("hide", "mask"); + } + /** * 响应显示层事件 */ - private handleShowLayer = (e: K) => { + private handleShowLayer = (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).emit("hide", layer.key); + } + }); + } + + // 显示蒙版 + if (e !== "mask" && e !== "occlude") + (this as Emitter).emit("show", "mask"); + // 取消消失定时 displayLayer.disappearTimer && clearTimeout(displayLayer.disappearTimer); + displayLayer.isShow = true; + displayLayer.isDisplay = true; this.setData({ [`${ e }$isShow`]: true, [`${ e }$isDisplay`]: true @@ -109,18 +172,66 @@ class PopupLayer< /** * 响应隐藏层事件 */ - private handleHideLayer = (e: K) => { + private handleHideLayer = (e: K) => { let displayLayer = this.getDisplayLayer(e); - this.setData({ - [`${ e }$isShow`]: false - }); + // 阻止未发生的变化 + if (!displayLayer.isShow) return; - displayLayer.disappearTimer = setTimeout(() => { + if (displayLayer.animateTime <= 0) { + + displayLayer.isShow = false; + displayLayer.isDisplay = false; this.setData({ + [`${ e }$isShow`]: false, [`${ e }$isDisplay`]: false }); - }, displayLayer.animateTime); + } else { + + displayLayer.isShow = false; + this.setData({ + [`${ e }$isShow`]: false + }); + + // 开启遮蔽 + if (this.showOccludeWhenHide) { + (this as Emitter).emit("show", "occlude"); + } + + displayLayer.disappearTimer = setTimeout(() => { + displayLayer.isDisplay = false; + this.setData({ + [`${ e }$isDisplay`]: false + }); + + // 取消 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).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).emit("hide", "mask"); + } this.emit("change", displayLayer); } diff --git a/miniprogram/pages/Account/Account.scss b/miniprogram/pages/Account/Account.scss index 32a102d..1d6a5d1 100644 --- a/miniprogram/pages/Account/Account.scss +++ b/miniprogram/pages/Account/Account.scss @@ -1,7 +1,7 @@ @import "./UserCard.scss"; @import "./MainFunction.scss"; @import "./FunctionList.scss"; -@import "../../modular/Mask/Mask.scss"; +@import "../../modular/PopupLayer.scss"; view.container{ padding-top: 50rpx; diff --git a/miniprogram/pages/Account/Account.ts b/miniprogram/pages/Account/Account.ts index df02ab1..8b8d035 100644 --- a/miniprogram/pages/Account/Account.ts +++ b/miniprogram/pages/Account/Account.ts @@ -3,18 +3,29 @@ import { UserCard } from "./UserCard"; import { MainFunction } from "./MainFunction"; import { FunctionList } from "./FunctionList"; import { PopupLayer } from "../../modular/PopupLayer"; +import { TestLayerA } from "./TestLayerA"; (async () => { // 初始化页面 const { manager, query } = await Manager.PageAsync(); - // 添加蒙版 Modular - const popupLayer: PopupLayer<"a" | "b"> = manager.addModule(PopupLayer, "mask") as any; - popupLayer.emit("show", "a"); + // 添加弹出层 Modular + const popupLayer: PopupLayer<"layerA" | "layerB"> = manager.addModule(PopupLayer, "mask") as any; // 添加 UserCard Modular - manager.addModule(UserCard, "userCard"); + const userCard = manager.addModule(UserCard, "userCard"); + + //#region test layer + // popupLayer.hideOtherWhenShow = false; + const testLayerA = manager.addModule(TestLayerA, "testLayerA"); + userCard.on("clickChangeTheme", () => { + popupLayer.emit("show", "layerA"); + }) + testLayerA.on("click", () => { + popupLayer.emit("show", "layerB"); + }) + //#endregion // 添加 MainFunction Modular manager.addModule(MainFunction, "mainFunction"); diff --git a/miniprogram/pages/Account/Account.wxml b/miniprogram/pages/Account/Account.wxml index 3b2b252..99d4fc5 100644 --- a/miniprogram/pages/Account/Account.wxml +++ b/miniprogram/pages/Account/Account.wxml @@ -1,6 +1,18 @@ + + + - + + + + + layerA(点击显示layerB) + + + + + layerB + diff --git a/miniprogram/pages/Account/TestLayerA.ts b/miniprogram/pages/Account/TestLayerA.ts new file mode 100644 index 0000000..f45a2c2 --- /dev/null +++ b/miniprogram/pages/Account/TestLayerA.ts @@ -0,0 +1,26 @@ +import { Modular, Manager } from "../../core/Module"; + +type IUserCardEvent = { + + /** + * 主题更换按钮点击事件 + */ + click: void; +} + +class TestLayerA extends Modular { + + public override onLoad() { + this.setFunc(this.handleClick, "click"); + } + + /** + * 弹窗点击时 + */ + private handleClick() { + this.emit("click"); + } +} + +export { TestLayerA }; +export default TestLayerA; \ No newline at end of file diff --git a/miniprogram/pages/Account/UserCard.ts b/miniprogram/pages/Account/UserCard.ts index f6c54f8..5646a71 100644 --- a/miniprogram/pages/Account/UserCard.ts +++ b/miniprogram/pages/Account/UserCard.ts @@ -1,9 +1,4 @@ import { Modular, Manager } from "../../core/Module"; -import { Mask } from "../../modular/Mask/Mask"; - -type IUserCardDependent = { - // mask: Mask -} type IUserCardEvent = { @@ -13,17 +8,16 @@ type IUserCardEvent = { clickChangeTheme: void; } -class UserCard extends Modular, IUserCardEvent> { +class UserCard extends Modular { public override onLoad() { - this.setFunc(this.handleChangeTheme, "changeTheme") + this.setFunc(this.handleChangeTheme, "changeTheme"); } /** * 处理主题更换 */ private handleChangeTheme() { - // this.depends?.mask.emit("show", void 0); this.emit("clickChangeTheme"); } }