(#36) Merge mask modular & popup modular in popup layer modular. #63

Merged
MrKBear merged 2 commits from dev-mrkbear into master 2022-01-24 14:59:34 +08:00
10 changed files with 286 additions and 189 deletions
Showing only changes of commit 18381aa0c4 - Show all commits

View File

@ -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 );

View File

@ -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;
}
}

View File

@ -1,115 +0,0 @@
import { Modular, Manager } from "../../core/Module";
/**
*
*/
type IMaskEvent = {
/**
*
*/
show: void;
/**
*
*/
hide: void;
/**
*
*/
change: boolean;
/**
*
*/
click: void;
}
/**
* Modular
*/
class Mask<M extends Manager> extends Modular<M, {}, IMaskEvent> {
/**
*
*/
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;

View File

@ -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);
}
}

View File

@ -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<L extends string> = {
change: Readonly<DisplayLayer>;
}
type commonLayerType = "mask" | "occlude";
/**
*
*/
class PopupLayer<
L extends string,
M extends Manager = Manager
> extends Modular<M, {}, IPopupLayerEvent<L>> {
> extends Modular<M, {}, IPopupLayerEvent<L | commonLayerType>> {
/**
*
*/
public autoCloseOnClick: boolean = true;
/**
*
*/
public showOccludeWhenHide: boolean = true;
/**
* Layer
*/
public hideOtherWhenShow: boolean = true;
/**
*
*/
private layers: Map<L, DisplayLayer> = new Map();
private layers: Map<L | commonLayerType, DisplayLayer> = 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<K extends L>(e: K): DisplayLayer {
private getDisplayLayer<K extends L | commonLayerType>(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<IAnyData>).emit("hide", layer.key);
});
// 关闭蒙版
(this as Emitter<IAnyData>).emit("hide", "mask");
}
/**
*
*/
private handleShowLayer = <K extends L>(e: K) => {
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.setData({
[`${ e }$isShow`]: true,
[`${ e }$isDisplay`]: true
@ -109,18 +172,66 @@ class PopupLayer<
/**
*
*/
private handleHideLayer = <K extends L>(e: K) => {
private handleHideLayer = <K extends L | commonLayerType>(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<IAnyData>).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<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);
}

View File

@ -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;

View File

@ -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");

View File

@ -1,6 +1,18 @@
<!-- 层遮蔽层 -->
<view class="occlude {{ mask$occlude$isShow ? 'show-fade' : 'hide-fade' }} {{ mask$occlude$isDisplay ? 'block' : 'none' }}" bindtap="mask$clickMask"></view>
<!-- 蒙版 -->
<view class="mask {{ mask$isShow ? 'show' : 'hide' }} {{ mask$isDisplay ? 'block' : 'none' }}"
bindtap="mask$handleClickMask"></view>
<view class="mask {{ mask$mask$isShow ? 'show-fade' : 'hide-fade' }} {{ mask$mask$isDisplay ? 'block' : 'none' }}" bindtap="mask$clickMask"></view>
<!-- 层A -->
<view class="layer {{ mask$layerA$isShow ? 'show-scale' : 'hide-scale' }} {{ mask$layerA$isDisplay ? 'block' : 'none' }}" bindtap="mask$clickMask">
<view class="card" style="height: 300px; line-height: 300px; text-align:center" catchtap="testLayerA$click">layerA(点击显示layerB)</view>
</view>
<!-- 层B -->
<view class="layer {{ mask$layerB$isShow ? 'show-scale' : 'hide-scale' }} {{ mask$layerB$isDisplay ? 'block' : 'none' }}" bindtap="mask$clickMask">
<view class="card" style="height: 200px; line-height: 200px; text-align:center" catchtap>layerB</view>
</view>
<!-- 顶部的阴影 -->
<view class="top-shadow"></view>

View File

@ -0,0 +1,26 @@
import { Modular, Manager } from "../../core/Module";
type IUserCardEvent = {
/**
*
*/
click: void;
}
class TestLayerA<M extends Manager> extends Modular<M, {}, IUserCardEvent> {
public override onLoad() {
this.setFunc(this.handleClick, "click");
}
/**
*
*/
private handleClick() {
this.emit("click");
}
}
export { TestLayerA };
export default TestLayerA;

View File

@ -1,9 +1,4 @@
import { Modular, Manager } from "../../core/Module";
import { Mask } from "../../modular/Mask/Mask";
type IUserCardDependent<M extends Manager> = {
// mask: Mask<M>
}
type IUserCardEvent = {
@ -13,17 +8,16 @@ type IUserCardEvent = {
clickChangeTheme: void;
}
class UserCard<M extends Manager> extends Modular<M, IUserCardDependent<M>, IUserCardEvent> {
class UserCard<M extends Manager> extends Modular<M, {}, IUserCardEvent> {
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");
}
}