12 Commits
Author SHA1 Message Date
yzy 49851d4a57 (#36) Add popups 2022-01-21 20:11:11 +08:00
MrKBear df4229bf2f Merge 'master' into dev-yzy 2022-01-21 20:04:13 +08:00
MrKBear 43d87b40f7 Merge pull request '(#21) Mixin IAnyData in app' (#59) from dev-mrkbear into master
Reviewed-on: http://git.mrkbear.com/MrKBear/mini-dlpu-v3/pulls/59
2022-01-21 17:39:13 +08:00
MrKBear 660f6921de (#21) Mixin IAnyData in app 2022-01-21 17:38:41 +08:00
MrKBear 86101e01d1 Merge pull request '(#22) Add StudentInfo file' (#58) from dev-mrkbear into master
Reviewed-on: http://git.mrkbear.com/MrKBear/mini-dlpu-v3/pulls/58
2022-01-21 17:37:05 +08:00
MrKBear 1f2a2ad6bd (#22) Add StudentInfo file 2022-01-21 17:36:16 +08:00
MrKBear b91a9271a7 Merge pull request '(#56) Add Core Data.' (#57) from dev-mrkbear into master
Reviewed-on: http://git.mrkbear.com/MrKBear/mini-dlpu-v3/pulls/57
2022-01-21 17:33:10 +08:00
MrKBear ec635b9ae6 (#56) Add Core Data. 2022-01-21 17:30:08 +08:00
MrKBear 6f96a69900 Merge pull request '(#35)Add mask modular event.' (#55) from dev-mrkbear into master
Reviewed-on: http://git.mrkbear.com/MrKBear/mini-dlpu-v3/pulls/55
2022-01-21 10:43:24 +08:00
MrKBear 58d8d74158 (#35)Add mask modular event. 2022-01-21 10:38:37 +08:00
MrKBear 96b3414d22 Merge pull request '(#28)Add a api frame (incomplete file)' (#51) from dev-tamako into master
Reviewed-on: http://git.mrkbear.com/MrKBear/mini-dlpu-v3/pulls/51
2022-01-20 23:52:35 +08:00
yzy cd8ca7dcc4 #36 Add basic popups 2022-01-20 12:49:02 +08:00
11 changed files with 447 additions and 15 deletions
+2 -2
View File
@@ -1,9 +1,9 @@
import { IAppAPIParam } from "./core/Api";
import { IAppAPIParam, IAnyData } from "./core/Api";
import { IAppStorageParam, Storage, IStorageData } from "./core/Storage";
import { Logger, LevelLogLabel, LifeCycleLogLabel } from "./core/Logger";
App<IAppAPIParam & IAppStorageParam>({
App<IAppAPIParam & IAppStorageParam & IAnyData>({
/**
* API 模块需要的全局数据
+250
View File
@@ -0,0 +1,250 @@
/**
* 数据层键值设置
*/
interface IDataParamSettingItem {
/**
* 类型
*/
type: any;
/**
* 键值是否可以获取
*/
isGet: boolean;
/**
* 键值是否可以设置
*/
isSet: boolean;
/**
* 是否仅为异步获取
*/
isGetAsync?: boolean;
/**
* 是否仅为异步设置
*/
isSetAsync?: boolean;
}
/**
* 数据层参数类型
*/
interface IDataParamSetting {
[x: string]: IDataParamSettingItem
}
type IGet<T> = () => T;
type IGetAsync<T> = () => Promise<T>;
type ISet<T> = (data: T) => INone;
type ISetAsync<T> = (data: T) => Promise<INone>;
type INone = undefined | void | unknown;
/**
* 注册表结构
*/
type IRegistryItem<S extends IDataParamSettingItem> = {
/**
* 获取方法
*/
get: S["isGetAsync"] extends true ? INone : S["isGet"] extends true ? IGet<S["type"]> : INone;
/**
* 异步获取方法
*/
getAsync: S["isGet"] extends true ? IGetAsync<S["type"]> : INone;
/**
* 设置方法
*/
set: S["isSetAsync"] extends true ? INone : S["isSet"] extends true ? ISet<S["type"]> : INone;
/**
* 异步设置方法
*/
setAsync: S["isSet"] extends true ? ISetAsync<S["type"]> : INone;
}
/**
* 注册表参数类型
*/
type IRegistry<D extends IDataParamSetting> = {
[P in keyof D]: IRegistryItem<D[P]>;
}
type IRegistryPartial<D extends IDataParamSetting> = {
[P in keyof D]?: Partial<IRegistryItem<D[P]>>;
}
type IAutoSelect<IF extends boolean, A, B> = IF extends true ? A : B;
/**
* Core 数据层架构
*
* 使用示例:
* ```typescript
* class TestData extends Data<{
* test: {
* type: number,
* isGet: true,
* isSet: true,
* isGetAsync: true
* }
* }> {
* public onLoad() {
* let dataObject = {key: 1}
* this.getter("test", () => 1);
* this.registerKeyFromObject("test", "key", dataObject);
* }
* }
* ```
*/
class Data<D extends IDataParamSetting> {
/**
* getter setter 注册表
*/
private registryList: IRegistryPartial<D> = {};
/**
* 加载函数
*/
public onLoad(): any {};
/**
* 注册一个 Setter 到键值上
* @param key 注册的键值
* @param setter 注册的 Setter
* @param isAsync 是否为异步函数
*/
protected setter<KEY extends keyof D> (key: KEY, setter: IRegistryItem<D[KEY]>["set"]): this
protected setter<KEY extends keyof D> (key: KEY, setter: IRegistryItem<D[KEY]>["setAsync"], isAsync: true): this
protected setter<
KEY extends keyof D,
ASYNC extends boolean
> (
key: KEY,
setter: IAutoSelect<ASYNC, IRegistryItem<D[KEY]>["setAsync"], IRegistryItem<D[KEY]>["set"]>,
isAsync?: ASYNC
): this {
// 如果此键值不存在,新建
if (!this.registryList[key]) this.registryList[key] = {};
// 设置异步 setter
if (isAsync) this.registryList[key]!.setAsync = setter as IRegistryItem<D[KEY]>["setAsync"];
// 设置同步 setter
else this.registryList[key]!.set = setter as IRegistryItem<D[KEY]>["set"];
return this;
}
/**
* 注册一个 Getter 到键值上
* @param key 注册的键值
* @param getter 注册的 Getter
* @param isAsync 是否为异步函数
*/
protected getter<KEY extends keyof D> (key: KEY, getter: IRegistryItem<D[KEY]>["get"]): this
protected getter<KEY extends keyof D> (key: KEY, getter: IRegistryItem<D[KEY]>["getAsync"], isAsync: true): this
protected getter<
KEY extends keyof D,
ASYNC extends boolean
> (
key: KEY,
getter: IAutoSelect<ASYNC, IRegistryItem<D[KEY]>["getAsync"], IRegistryItem<D[KEY]>["get"]>,
isAsync?: ASYNC
): this {
// 如果此键值不存在,新建
if (!this.registryList[key]) this.registryList[key] = {};
// 设置异步 getter
if (isAsync) this.registryList[key]!.getAsync = getter as IRegistryItem<D[KEY]>["getAsync"];
// 设置同步 getter
else this.registryList[key]!.get = getter as IRegistryItem<D[KEY]>["get"];
return this;
}
/**
* 将对象的键值关联到 Data 层中
* @param key Data 层键值
* @param keyFromObject 对象源键值
* @param object 关联对象
*/
protected registerKeyFromObject<
KEY extends keyof D,
F extends keyof O,
O extends {[K in F]: D[KEY]["type"]}
> (key: KEY, keyFromObject: F, object: O) {
// 注册同步获取
this.getter(key, () => {
return object[keyFromObject]
});
// 注册同步设置
this.setter(key, (data: any) => {
object[keyFromObject] = data
})
}
/**
* 导出数据对象
* @returns 数据对象
*/
public export(): IRegistry<D> {
this.autoFillFunction();
return this.registryList as IRegistry<D>;
}
/**
* 自动填充缺失的异步函数
* 在注册表中搜索全部的同步函数
* 并自动填充对应的异步函数
* 此函数会在 export 前静默执行
*/
protected autoFillFunction(): void {
// 填充函数
const fillFunction = <KEY extends keyof D>(key: KEY): void => {
const item = this.registryList[key] as IRegistryItem<D[KEY]>;
if (!item) return;
// 检验 getter
if (item.get && !item.getAsync) {
item.getAsync = this.syncFn2AsyncFn(item.get as IGet<D[KEY]["type"]>);
}
// 检验 setter
if (item.set && !item.setAsync) {
item.setAsync = this.syncFn2AsyncFn(item.set as ISet<D[KEY]["type"]>);
}
}
// 在注册表中查找
for (const key in this.registryList) fillFunction(key);
}
/**
* 将同步函数转换为异步函数
* @param fn 同步函数
*/
protected syncFn2AsyncFn<D, H extends (IGet<D> | ISet<D>)> (fn: H):
IAutoSelect<H extends IGet<D> ? true : false, IGetAsync<D>, ISetAsync<D>> {
const asyncFn = async (...param: [D]) => {
return fn(...param);
};
return asyncFn as any;
}
}
View File
+59 -10
View File
@@ -1,6 +1,35 @@
import { Modular, Manager } from "../../core/Module";
class Mask<M extends Manager> extends Modular<M> {
/**
* 蒙版事件
*/
type IMaskEvent = {
/**
* 蒙版显示事件
*/
show: void;
/**
* 蒙版隐藏事件
*/
hide: void;
/**
* 蒙版状态改变事件
*/
change: boolean;
/**
* 蒙版点击事件
*/
click: void;
}
/**
* 蒙版 Modular
*/
class Mask<M extends Manager> extends Modular<M, {}, IMaskEvent> {
/**
* 动画运行时间
@@ -25,22 +54,41 @@ class Mask<M extends Manager> extends Modular<M> {
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);
}
/**
* 显示蒙版
*/
public showMask() {
private showMask = () => {
this.disappearTimer && clearTimeout(this.disappearTimer);
this.setData({
isShow: true,
isDisplay: true
});
this.emit("change", true);
}
/**
* 隐藏蒙版
*/
public hideMask() {
private hideMask = () => {
this.setData({
isShow: false
});
@@ -50,15 +98,16 @@ class Mask<M extends Manager> extends Modular<M> {
isDisplay: false
});
}, Mask.animateTime);
}
public override onLoad() {
this.setFunc(this.handleClickMask, "handleClickMask");
// Do something
}
this.emit("change", false);
}
/**
* 处理蒙版点击事件
*/
private handleClickMask() {
this.hideMask();
if (this.autoCloseOnClick) this.emit("hide", void 0);
this.emit("click", void 0);
}
}
+49
View File
@@ -0,0 +1,49 @@
@import "../../app.scss";
view.popups {
position: fixed;
width: 75%;
height: 75%;
margin:auto;
left:0;
right:0;
top:0;
bottom:0;
background-color: $theme-color-light-layout;
border-radius: 15px;
z-index: 2;
}
view.popups.block {
display: block;
}
view.popups.none {
display: none;
}
view.popups.show {
animation-duration: 0.5s;
animation-name: show;
}
view.popups.hide {
animation-duration: 0.5s;
animation-name: hide;
}
@keyframes show{
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes hide{
from {
opacity: 1;
}
to {
opacity: 0;
}
}
+58
View File
@@ -0,0 +1,58 @@
import { Modular, Manager } from "../../core/Module";
class Popups<M extends Manager> extends Modular<M> {
/**
* 动画运行时间
*/
public static readonly animateTime: number = 100;
public data? = {
/**
* 弹出层是否显示
*/
display:false,
/**
* 弹出层动画
*/
isShow:false
};
disappearTimer: number | undefined;
/**
* 显示弹出层
*/
public showPopups() {
this.setData({
isShow:true,
display:true
});
}
/**
* 隐藏弹出层
*/
public hidePopups() {
this.setData({
isShow:false
});
this.disappearTimer = setTimeout(() => {
this.setData({
display: false
});
}, Popups.animateTime);
}
public override onLoad() {
// Do something
}
}
export { Popups };
export default Popups;
+1
View File
@@ -2,6 +2,7 @@
@import "./MainFunction.scss";
@import "./FunctionList.scss";
@import "../../modular/Mask/Mask.scss";
@import "../../modular/Popups/Popups.scss";
view.container{
padding-top: 50rpx;
+4 -1
View File
@@ -3,6 +3,7 @@ import { UserCard } from "./UserCard";
import { MainFunction } from "./MainFunction";
import { FunctionList } from "./FunctionList";
import { Mask } from "../../modular/Mask/Mask";
import {Popups} from "../../modular/Popups/Popups"
(async () => {
@@ -12,8 +13,10 @@ import { Mask } from "../../modular/Mask/Mask";
// 添加蒙版 Modular
const mask = manager.addModule(Mask, "mask");
const popups = manager.addModule(Popups,"popups")
// 添加 UserCard Modular
manager.addModule(UserCard, "userCard", { mask });
manager.addModule(UserCard, "userCard", { mask, popups });
// 添加 MainFunction Modular
manager.addModule(MainFunction, "mainFunction");
+3
View File
@@ -2,6 +2,9 @@
<view class="mask {{ mask$isShow ? 'show' : 'hide' }} {{ mask$isDisplay ? 'block' : 'none' }}"
bindtap="mask$handleClickMask"></view>
<!-- 弹出层 -->
<view class="popups" style="display:{{popups$isShow ? 'block' : 'none'}}"></view>
<!-- 顶部的阴影 -->
<view class="top-shadow"></view>
+14 -2
View File
@@ -1,11 +1,21 @@
import Popups from "modular/Popups/Popups";
import { Modular, Manager } from "../../core/Module";
import { Mask } from "../../modular/Mask/Mask";
type IUserCardDependent<M extends Manager> = {
mask: Mask<M>
popups: Popups<M>
}
class UserCard<M extends Manager> extends Modular<M, IUserCardDependent<M>> {
type IUserCardEvent = {
/**
* 主题更换按钮点击事件
*/
clickChangeTheme: void;
}
class UserCard<M extends Manager> extends Modular<M, IUserCardDependent<M>, IUserCardEvent> {
public override onLoad() {
this.setFunc(this.handleChangeTheme, "changeTheme")
@@ -15,7 +25,9 @@ class UserCard<M extends Manager> extends Modular<M, IUserCardDependent<M>> {
* 处理主题更换
*/
private handleChangeTheme() {
this.depends?.mask.showMask();
this.depends?.popups.showPopups();
this.depends?.mask.emit("show", void 0);
this.emit("clickChangeTheme", void 0);
}
}
+7
View File
@@ -1,4 +1,5 @@
{
"setting": {},
"condition": {
"plugin": {
"list": []
@@ -16,6 +17,12 @@
"pathName": "pages/Account/Account",
"query": "",
"scene": null
},
{
"name": "pages/Account/Account",
"pathName": "pages/Account/Account",
"query": "",
"scene": null
}
]
}