Merge pull request 'Optimize Storage Modular' (#16) from dev-mrkbear into master
Reviewed-on: http://git.mrkbear.com/MrKBear/mini-dlpu-v3/pulls/16
This commit is contained in:
commit
de67ab0d68
@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
掌上教务处作为工业大学的社区开源项目,自从2017年开始已有近5年岁月,在无数同学的贡献之下,为大家打造便捷的校园服务。
|
掌上教务处作为工业大学的社区开源项目,自从2017年开始已有近5年岁月,在无数同学的贡献之下,为大家打造便捷的校园服务。
|
||||||
|
|
||||||
__*!!!注意!!!*__
|
__*!!!警告!!!*__
|
||||||
|
|
||||||
请在主仓库提交代码,而非镜像仓库!
|
请在主仓库提交代码,而非镜像仓库!在镜像仓库提交的代码将会在同步时被覆盖!
|
||||||
|
|
||||||
主仓库: http://git.mrkbear.com/MrKBear/mini-dlpu-v3
|
主仓库: http://git.mrkbear.com/MrKBear/mini-dlpu-v3
|
||||||
|
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { IAppAPIParam } from "./core/Api";
|
import { IAppAPIParam } from "./core/Api";
|
||||||
|
import { IAppStorageParam, Storage, IStorageData } from "./core/Storage";
|
||||||
import { Logger, LevelLogLabel, LifeCycleLogLabel } from "./core/Logger";
|
import { Logger, LevelLogLabel, LifeCycleLogLabel } from "./core/Logger";
|
||||||
|
|
||||||
|
|
||||||
App<IAppAPIParam>({
|
App<IAppAPIParam & IAppStorageParam>({
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* API 模块需要的全局数据
|
* API 模块需要的全局数据
|
||||||
@ -16,7 +17,7 @@ App<IAppAPIParam>({
|
|||||||
/**
|
/**
|
||||||
* 存储缓存键值
|
* 存储缓存键值
|
||||||
*/
|
*/
|
||||||
// storageCache: new Set<string>(),
|
storage: new Map<string, Storage<IStorageData>>(),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 小程序加载时
|
* 小程序加载时
|
||||||
|
@ -2,27 +2,18 @@ export type EventType = string | symbol;
|
|||||||
|
|
||||||
// An event handler can take an optional event argument
|
// An event handler can take an optional event argument
|
||||||
// and should not return a value
|
// and should not return a value
|
||||||
export type Handler<T = unknown> = (event: T) => void;
|
export type Handler<T = any> = (event: T) => void;
|
||||||
export type WildcardHandler<T = Record<string, unknown>> = (
|
|
||||||
type: keyof T,
|
|
||||||
event: T[keyof T]
|
|
||||||
) => void;
|
|
||||||
|
|
||||||
// An array of all currently registered event handlers for a type
|
// An array of all currently registered event handlers for a type
|
||||||
export type EventHandlerList<T = unknown> = Array<Handler<T>>;
|
export type EventHandlerList<T = any> = Array<Handler<T>>;
|
||||||
export type WildCardEventHandlerList<T = Record<string, unknown>> = Array<WildcardHandler<T>>;
|
|
||||||
|
|
||||||
// A map of event types and their corresponding event handlers.
|
// A map of event types and their corresponding event handlers.
|
||||||
export type EventHandlerMap<Events extends Record<EventType, unknown>> = Map<
|
export type EventHandlerMap<Events extends Record<EventType, any>> = Map<
|
||||||
keyof Events | '*',
|
keyof Events,
|
||||||
EventHandlerList<Events[keyof Events]> | WildCardEventHandlerList<Events>
|
EventHandlerList<Events[keyof Events]>
|
||||||
>;
|
>;
|
||||||
|
|
||||||
type GenericEventHandler<Events extends Record<EventType, unknown>> =
|
export class Emitter<Events extends Record<EventType, any>> {
|
||||||
| Handler<Events[keyof Events]>
|
|
||||||
| WildcardHandler<Events>;
|
|
||||||
|
|
||||||
export class Emitter<Events extends Record<EventType, unknown>> {
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Map of event names to registered handler functions.
|
* A Map of event names to registered handler functions.
|
||||||
@ -41,17 +32,14 @@ export class Emitter<Events extends Record<EventType, unknown>> {
|
|||||||
this.all!.set(type, [] as EventHandlerList<Events[keyof Events]>);
|
this.all!.set(type, [] as EventHandlerList<Events[keyof Events]>);
|
||||||
}
|
}
|
||||||
|
|
||||||
on<Key extends keyof Events>(type: Key, handler: Handler<Events[Key]>): void;
|
|
||||||
on(type: '*', handler: WildcardHandler<Events>): void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register an event handler for the given type.
|
* Register an event handler for the given type.
|
||||||
* @param {string|symbol} type Type of event to listen for, or `'*'` for all events
|
* @param {string|symbol} type Type of event to listen for
|
||||||
* @param {Function} handler Function to call in response to given event
|
* @param {Function} handler Function to call in response to given event
|
||||||
* @memberOf mitt
|
* @memberOf mitt
|
||||||
*/
|
*/
|
||||||
public on<Key extends keyof Events>(type: Key, handler: GenericEventHandler<Events>) {
|
public on<Key extends keyof Events>(type: Key, handler: Handler<Events[Key]>) {
|
||||||
const handlers: Array<GenericEventHandler<Events>> | undefined = this.all!.get(type);
|
const handlers: Array<Handler<Events[Key]>> | undefined = this.all!.get(type);
|
||||||
if (handlers) {
|
if (handlers) {
|
||||||
handlers.push(handler);
|
handlers.push(handler);
|
||||||
}
|
}
|
||||||
@ -60,18 +48,15 @@ export class Emitter<Events extends Record<EventType, unknown>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
off<Key extends keyof Events>(type: Key, handler?: Handler<Events[Key]>): void;
|
|
||||||
off(type: '*', handler: WildcardHandler<Events>): void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove an event handler for the given type.
|
* Remove an event handler for the given type.
|
||||||
* If `handler` is omitted, all handlers of the given type are removed.
|
* If `handler` is omitted, all handlers of the given type are removed.
|
||||||
* @param {string|symbol} type Type of event to unregister `handler` from, or `'*'`
|
* @param {string|symbol} type Type of event to unregister `handler` from
|
||||||
* @param {Function} [handler] Handler function to remove
|
* @param {Function} [handler] Handler function to remove
|
||||||
* @memberOf mitt
|
* @memberOf mitt
|
||||||
*/
|
*/
|
||||||
public off<Key extends keyof Events>(type: Key, handler?: GenericEventHandler<Events>) {
|
public off<Key extends keyof Events>(type: Key, handler?: Handler<Events[Key]>) {
|
||||||
const handlers: Array<GenericEventHandler<Events>> | undefined = this.all!.get(type);
|
const handlers: Array<Handler<Events[Key]>> | undefined = this.all!.get(type);
|
||||||
if (handlers) {
|
if (handlers) {
|
||||||
if (handler) {
|
if (handler) {
|
||||||
handlers.splice(handlers.indexOf(handler) >>> 0, 1);
|
handlers.splice(handlers.indexOf(handler) >>> 0, 1);
|
||||||
@ -82,20 +67,14 @@ export class Emitter<Events extends Record<EventType, unknown>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
emit<Key extends keyof Events>(type: Key, event: Events[Key]): void;
|
|
||||||
emit<Key extends keyof Events>(type: undefined extends Events[Key] ? Key : never): void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoke all handlers for the given type.
|
* Invoke all handlers for the given type.
|
||||||
* If present, `'*'` handlers are invoked after type-matched handlers.
|
|
||||||
*
|
|
||||||
* Note: Manually firing '*' handlers is not supported.
|
|
||||||
*
|
*
|
||||||
* @param {string|symbol} type The event type to invoke
|
* @param {string|symbol} type The event type to invoke
|
||||||
* @param {Any} [evt] Any value (object is recommended and powerful), passed to each handler
|
* @param {Any} [evt] Any value (object is recommended and powerful), passed to each handler
|
||||||
* @memberOf mitt
|
* @memberOf mitt
|
||||||
*/
|
*/
|
||||||
emit<Key extends keyof Events>(type: Key, evt?: Events[Key]) {
|
emit<Key extends keyof Events>(type: Key, evt: Events[Key]) {
|
||||||
let handlers = this.all!.get(type);
|
let handlers = this.all!.get(type);
|
||||||
if (handlers) {
|
if (handlers) {
|
||||||
(handlers as EventHandlerList<Events[keyof Events]>)
|
(handlers as EventHandlerList<Events[keyof Events]>)
|
||||||
@ -104,14 +83,5 @@ export class Emitter<Events extends Record<EventType, unknown>> {
|
|||||||
handler(evt!);
|
handler(evt!);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
handlers = this.all!.get('*');
|
|
||||||
if (handlers) {
|
|
||||||
(handlers as WildCardEventHandlerList<Events>)
|
|
||||||
.slice()
|
|
||||||
.map((handler) => {
|
|
||||||
handler(type, evt!);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
import { Emitter, EventType } from "./Emitter";
|
import { Emitter } from "./Emitter";
|
||||||
import { Logger, LogLabel, LogStyle, LevelLogLabel } from "./Logger";
|
import { Logger, LogLabel, colorRadio, LevelLogLabel } from "./Logger";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 自定义对象类型
|
* 自定义对象类型
|
||||||
@ -50,6 +50,149 @@ type Depends<M extends Manager<AnyWXContext>> = {
|
|||||||
[x:string]: Modular<M, Depends<M>>;
|
[x:string]: Modular<M, Depends<M>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 微信继承的函数
|
||||||
|
*/
|
||||||
|
class WXInstanceMethods<
|
||||||
|
E extends IAnyTypeObject = IAnyTypeObject,
|
||||||
|
W extends AnyWXContext = AnyWXContext
|
||||||
|
>
|
||||||
|
extends Emitter<E>
|
||||||
|
implements InstanceMethods<W["data"]> {
|
||||||
|
|
||||||
|
public superContext: W;
|
||||||
|
|
||||||
|
public constructor(context: W) {
|
||||||
|
super();
|
||||||
|
this.superContext = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
public setData(data: Partial<W["data"]> & WechatMiniprogram.IAnyObject, callback?: () => void): void {
|
||||||
|
return this.superContext.setData(data, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
public hasBehavior(behavior: string): void {
|
||||||
|
return this.superContext.hasBehavior(behavior);
|
||||||
|
}
|
||||||
|
|
||||||
|
public triggerEvent<DetailType = any>(name: string, detail?: DetailType, options?: WechatMiniprogram.Component.TriggerEventOption): void {
|
||||||
|
return this.superContext.triggerEvent(name, detail, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
public createSelectorQuery(): WechatMiniprogram.SelectorQuery {
|
||||||
|
return this.superContext.createSelectorQuery();
|
||||||
|
}
|
||||||
|
|
||||||
|
public createIntersectionObserver(options: WechatMiniprogram.CreateIntersectionObserverOption): WechatMiniprogram.IntersectionObserver {
|
||||||
|
return this.superContext.createIntersectionObserver(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
public selectComponent(selector: string): WechatMiniprogram.Component.TrivialInstance {
|
||||||
|
return this.superContext.selectComponent(selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
public selectAllComponents(selector: string): WechatMiniprogram.Component.TrivialInstance[] {
|
||||||
|
return this.superContext.selectAllComponents(selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
public selectOwnerComponent(): WechatMiniprogram.Component.TrivialInstance {
|
||||||
|
return this.superContext.selectOwnerComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getRelationNodes(relationKey: string): WechatMiniprogram.Component.TrivialInstance[] {
|
||||||
|
return this.superContext.getRelationNodes(relationKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public groupSetData(callback?: () => void): void {
|
||||||
|
return this.superContext.groupSetData(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getTabBar(): WechatMiniprogram.Component.TrivialInstance {
|
||||||
|
return this.superContext.getTabBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPageId(): string {
|
||||||
|
return this.superContext.getPageId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public animate(selector: string, keyFrames: WechatMiniprogram.Component.KeyFrame[], duration: number, callback?: () => void): void;
|
||||||
|
public animate(selector: string, keyFrames: WechatMiniprogram.Component.ScrollTimelineKeyframe[], duration: number,
|
||||||
|
scrollTimeline: WechatMiniprogram.Component.ScrollTimelineOption): void;
|
||||||
|
public animate(selector: any, keyFrames: any, duration: any, scrollTimeline?: any): void {
|
||||||
|
return this.superContext.animate(selector, keyFrames, duration, scrollTimeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
public clearAnimation(selector: string, callback: () => void): void;
|
||||||
|
public clearAnimation(selector: string, options?: WechatMiniprogram.Component.ClearAnimationOptions, callback?: () => void): void;
|
||||||
|
public clearAnimation(selector: any, options?: any, callback?: any): void {
|
||||||
|
return this.superContext.clearAnimation(selector, options, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getOpenerEventChannel(): WechatMiniprogram.EventChannel {
|
||||||
|
return this.superContext.getOpenerEventChannel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 微信继承的属性
|
||||||
|
*/
|
||||||
|
class WXInstanceProperties<
|
||||||
|
E extends IAnyTypeObject = IAnyTypeObject,
|
||||||
|
W extends AnyWXContext = AnyWXContext
|
||||||
|
>
|
||||||
|
extends WXInstanceMethods<E, W>
|
||||||
|
implements InstanceProperties {
|
||||||
|
|
||||||
|
public override superContext: W;
|
||||||
|
|
||||||
|
constructor(context: W) {
|
||||||
|
super(context);
|
||||||
|
this.superContext = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get is(): string { return this.superContext.is };
|
||||||
|
|
||||||
|
public get route(): string { return this.superContext.route };
|
||||||
|
|
||||||
|
public get options(): Record<string, string | undefined> { return this.superContext.options };
|
||||||
|
}
|
||||||
|
|
||||||
|
class WXILifetime<
|
||||||
|
E extends IAnyTypeObject = IAnyTypeObject,
|
||||||
|
W extends AnyWXContext = AnyWXContext
|
||||||
|
>
|
||||||
|
extends WXInstanceProperties<E, W>
|
||||||
|
implements ILifetime {
|
||||||
|
|
||||||
|
public onLoad(query: Record<string, string | undefined>): void | Promise<void> {};
|
||||||
|
|
||||||
|
public onShow(): void | Promise<void> {};
|
||||||
|
|
||||||
|
public onReady(): void | Promise<void> {};
|
||||||
|
|
||||||
|
public onHide(): void | Promise<void> {};
|
||||||
|
|
||||||
|
public onUnload(): void | Promise<void> {};
|
||||||
|
|
||||||
|
public onPullDownRefresh(): void | Promise<void> {};
|
||||||
|
|
||||||
|
public onReachBottom(): void | Promise<void> {};
|
||||||
|
|
||||||
|
public onShareAppMessage(options: WechatMiniprogram.Page.IShareAppMessageOption): void | WechatMiniprogram.Page.ICustomShareContent {};
|
||||||
|
|
||||||
|
public onShareTimeline(): void | WechatMiniprogram.Page.ICustomTimelineContent {};
|
||||||
|
|
||||||
|
public onPageScroll(options: WechatMiniprogram.Page.IPageScrollOption): void | Promise<void> {};
|
||||||
|
|
||||||
|
public onTabItemTap(options: WechatMiniprogram.Page.ITabItemTapOption): void | Promise<void> {};
|
||||||
|
|
||||||
|
public onResize(options: WechatMiniprogram.Page.IResizeOption): void | Promise<void> {};
|
||||||
|
|
||||||
|
public onAddToFavorites(options: WechatMiniprogram.Page.IAddToFavoritesOption): WechatMiniprogram.Page.IAddToFavoritesContent {
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 页面模组
|
* 页面模组
|
||||||
* @template M 所属 Manager
|
* @template M 所属 Manager
|
||||||
@ -60,9 +203,10 @@ type Depends<M extends Manager<AnyWXContext>> = {
|
|||||||
class Modular<
|
class Modular<
|
||||||
M extends Manager<AnyWXContext> = Manager<AnyWXContext>,
|
M extends Manager<AnyWXContext> = Manager<AnyWXContext>,
|
||||||
DEP extends Depends<M> = Depends<M>,
|
DEP extends Depends<M> = Depends<M>,
|
||||||
E extends Record<EventType, unknown> = Record<EventType, unknown>,
|
E extends IAnyTypeObject = IAnyTypeObject,
|
||||||
TD extends IAnyTypeObject = IAnyTypeObject>
|
TD extends IAnyTypeObject = IAnyTypeObject
|
||||||
extends Emitter<E>
|
>
|
||||||
|
extends WXILifetime<E, M["context"]>
|
||||||
implements WXContext<TD, IAnyTypeObject> {
|
implements WXContext<TD, IAnyTypeObject> {
|
||||||
|
|
||||||
// [x:string]: any;
|
// [x:string]: any;
|
||||||
@ -95,7 +239,7 @@ implements WXContext<TD, IAnyTypeObject> {
|
|||||||
public functionList:Set<string>;
|
public functionList:Set<string>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 函数使用的参数列表
|
* 模组使用的参数列表
|
||||||
*/
|
*/
|
||||||
public paramList:Set<string>;
|
public paramList:Set<string>;
|
||||||
|
|
||||||
@ -104,13 +248,6 @@ implements WXContext<TD, IAnyTypeObject> {
|
|||||||
*/
|
*/
|
||||||
public nameSpace:string;
|
public nameSpace:string;
|
||||||
|
|
||||||
// 映射主上下文属性
|
|
||||||
public get is():string { return this.context.is };
|
|
||||||
public get route():string { return this.context.route };
|
|
||||||
public get options():Record<string, string | undefined> {
|
|
||||||
return this.context.options;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 一旦被类被构造,整个页面的全部申明周期将
|
* 一旦被类被构造,整个页面的全部申明周期将
|
||||||
* 由该类实例控制,此后请勿修改任何生命周期函数
|
* 由该类实例控制,此后请勿修改任何生命周期函数
|
||||||
@ -120,7 +257,7 @@ implements WXContext<TD, IAnyTypeObject> {
|
|||||||
*/
|
*/
|
||||||
public constructor(manager:M, nameSpace:string, depend?: DEP) {
|
public constructor(manager:M, nameSpace:string, depend?: DEP) {
|
||||||
|
|
||||||
super();
|
super(manager.context);
|
||||||
|
|
||||||
// 保存微信上下文
|
// 保存微信上下文
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
@ -134,7 +271,7 @@ implements WXContext<TD, IAnyTypeObject> {
|
|||||||
this.nameSpace = nameSpace;
|
this.nameSpace = nameSpace;
|
||||||
}
|
}
|
||||||
|
|
||||||
public setData(data:Partial<TD>, callback?: () => void):void {
|
public override setData(data:Partial<TD>, callback?: () => void):void {
|
||||||
|
|
||||||
if(this.data === void 0) {
|
if(this.data === void 0) {
|
||||||
this.data = {} as TD;
|
this.data = {} as TD;
|
||||||
@ -162,76 +299,6 @@ implements WXContext<TD, IAnyTypeObject> {
|
|||||||
(this.context as IAnyTypeObject)
|
(this.context as IAnyTypeObject)
|
||||||
[`${ this.nameSpace }$${ name }`] = fn.bind(this);
|
[`${ this.nameSpace }$${ name }`] = fn.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
//#region 映射微信的继承函数
|
|
||||||
|
|
||||||
public hasBehavior(behavior: string): void {
|
|
||||||
return this.context.hasBehavior(behavior);
|
|
||||||
}
|
|
||||||
|
|
||||||
public triggerEvent<DetailType>(name: string, detail?: DetailType,
|
|
||||||
options?: WechatMiniprogram.Component.TriggerEventOption): void {
|
|
||||||
return this.context.triggerEvent<DetailType>(name, detail, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
public createSelectorQuery(): WechatMiniprogram.SelectorQuery {
|
|
||||||
return this.context.createSelectorQuery();
|
|
||||||
}
|
|
||||||
|
|
||||||
public createIntersectionObserver(options: WechatMiniprogram.CreateIntersectionObserverOption):
|
|
||||||
WechatMiniprogram.IntersectionObserver {
|
|
||||||
return this.context.createIntersectionObserver(options);
|
|
||||||
}
|
|
||||||
|
|
||||||
public selectComponent(selector: string): WechatMiniprogram.Component.TrivialInstance {
|
|
||||||
return this.context.selectComponent(selector);
|
|
||||||
}
|
|
||||||
|
|
||||||
public selectAllComponents(selector: string): WechatMiniprogram.Component.TrivialInstance[] {
|
|
||||||
return this.context.selectAllComponents(selector);
|
|
||||||
}
|
|
||||||
|
|
||||||
public selectOwnerComponent(): WechatMiniprogram.Component.TrivialInstance {
|
|
||||||
return this.context.selectOwnerComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
public getRelationNodes(relationKey: string): WechatMiniprogram.Component.TrivialInstance[] {
|
|
||||||
return this.context.getRelationNodes(relationKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
public groupSetData(callback?: () => void): void {
|
|
||||||
return this.context.groupSetData(callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
public getTabBar(): WechatMiniprogram.Component.TrivialInstance {
|
|
||||||
return this.context.getTabBar();
|
|
||||||
}
|
|
||||||
|
|
||||||
public getPageId(): string {
|
|
||||||
return this.context.getPageId();
|
|
||||||
}
|
|
||||||
|
|
||||||
public animate(selector: string, keyFrames: WechatMiniprogram.Component.KeyFrame[],
|
|
||||||
duration: number, callback?: () => void): void;
|
|
||||||
public animate(selector: string, keyFrames: WechatMiniprogram.Component.ScrollTimelineKeyframe[],
|
|
||||||
duration: number, scrollTimeline: WechatMiniprogram.Component.ScrollTimelineOption): void;
|
|
||||||
public animate(selector: any, keyFrames: any, duration: any, scrollTimeline?: any): void {
|
|
||||||
return this.context.animate(selector, keyFrames, duration, scrollTimeline);
|
|
||||||
}
|
|
||||||
|
|
||||||
public clearAnimation(selector: string, callback: () => void): void;
|
|
||||||
public clearAnimation(selector: string, options?: WechatMiniprogram.Component.ClearAnimationOptions,
|
|
||||||
callback?: () => void): void;
|
|
||||||
public clearAnimation(selector: any, options?: any, callback?: any): void {
|
|
||||||
return this.context.clearAnimation(selector, options, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
public getOpenerEventChannel(): WechatMiniprogram.EventChannel {
|
|
||||||
return this.context.getOpenerEventChannel();
|
|
||||||
}
|
|
||||||
|
|
||||||
//#endregion
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -244,19 +311,9 @@ class Manager<WXC extends AnyWXContext = AnyWXContext> {
|
|||||||
* 微信生命周期
|
* 微信生命周期
|
||||||
*/
|
*/
|
||||||
static readonly WxLifeCycle:(keyof ILifetime)[] = [
|
static readonly WxLifeCycle:(keyof ILifetime)[] = [
|
||||||
"onShow",
|
"onShow", "onReady", "onHide", "onUnload", "onPullDownRefresh", "onReachBottom",
|
||||||
"onReady",
|
"onShareAppMessage", "onShareTimeline","onAddToFavorites","onPageScroll", "onResize", "onTabItemTap"
|
||||||
"onHide",
|
];
|
||||||
"onUnload",
|
|
||||||
"onPullDownRefresh",
|
|
||||||
"onReachBottom",
|
|
||||||
"onShareAppMessage",
|
|
||||||
"onShareTimeline",
|
|
||||||
"onAddToFavorites",
|
|
||||||
"onPageScroll",
|
|
||||||
"onResize",
|
|
||||||
"onTabItemTap"
|
|
||||||
]
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保存页面上下文
|
* 保存页面上下文
|
||||||
@ -288,9 +345,10 @@ class Manager<WXC extends AnyWXContext = AnyWXContext> {
|
|||||||
* @param depend 模块依赖
|
* @param depend 模块依赖
|
||||||
* @returns 模块实例
|
* @returns 模块实例
|
||||||
*/
|
*/
|
||||||
public addModule<DEP extends Depends<this>, M extends Modular<this, DEP>>
|
public addModule<DEP extends Depends<this>, M extends Modular<this, DEP>> (
|
||||||
(mode: new (manager:Manager<WXC>, nameSpace:string, depend?:DEP) => M,
|
mode: new (manager:this, nameSpace:string, depend?:DEP) => M,
|
||||||
nameSpace:string, depend?:DEP):M {
|
nameSpace:string, depend?:DEP
|
||||||
|
):M {
|
||||||
let mod = new mode(this, nameSpace, depend);
|
let mod = new mode(this, nameSpace, depend);
|
||||||
this.modules.push(mod);
|
this.modules.push(mod);
|
||||||
return mod;
|
return mod;
|
||||||
@ -300,14 +358,14 @@ class Manager<WXC extends AnyWXContext = AnyWXContext> {
|
|||||||
* 创建指定生命周期的钩子
|
* 创建指定生命周期的钩子
|
||||||
* @param key 生命周期键值
|
* @param key 生命周期键值
|
||||||
*/
|
*/
|
||||||
public creatHooks(key:keyof ILifetime):(...arg: any[]) => Promise<any> {
|
public creatHooks<Key extends keyof ILifetime>(key: Key): ILifetime[Key] {
|
||||||
return async (...arg: any[]) => {
|
let hook = (async (...arg: any[]) => {
|
||||||
|
|
||||||
let hooks:Promise<any>[] = [];
|
let hooks:Promise<any>[] = [];
|
||||||
|
|
||||||
for(let i = 0; i < this.modules.length; i++) {
|
for(let i = 0; i < this.modules.length; i++) {
|
||||||
|
|
||||||
let fn:Function = (this.modules[i] as IAnyTypeObject)[key];
|
let fn:Function = this.modules[i][key];
|
||||||
|
|
||||||
if(fn === void 0) continue;
|
if(fn === void 0) continue;
|
||||||
let res: Promise<any> | any = fn.apply(this.modules[i], arg);
|
let res: Promise<any> | any = fn.apply(this.modules[i], arg);
|
||||||
@ -340,7 +398,10 @@ class Manager<WXC extends AnyWXContext = AnyWXContext> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Promise.all(hooks);
|
return Promise.all(hooks);
|
||||||
}
|
});
|
||||||
|
|
||||||
|
// TODO: 此处为,关键位置,容易出错,请再次检查
|
||||||
|
return (hook as any);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -383,7 +444,7 @@ class Manager<WXC extends AnyWXContext = AnyWXContext> {
|
|||||||
this.context.setData(this.context.data);
|
this.context.setData(this.context.data);
|
||||||
|
|
||||||
// 调用全部模块的 onLoad 周期
|
// 调用全部模块的 onLoad 周期
|
||||||
let res = this.creatHooks("onLoad")(query as any);
|
let res = this.creatHooks("onLoad")(query);
|
||||||
|
|
||||||
// 打印每个模块的键值对使用情况
|
// 打印每个模块的键值对使用情况
|
||||||
for(let i = 0; i < this.modules.length; i++) {
|
for(let i = 0; i < this.modules.length; i++) {
|
||||||
@ -411,9 +472,9 @@ class Manager<WXC extends AnyWXContext = AnyWXContext> {
|
|||||||
/**
|
/**
|
||||||
* 模块被添加时的标签
|
* 模块被添加时的标签
|
||||||
*/
|
*/
|
||||||
public static readonly AddModuleLabel = new LogLabel("addModule",
|
public static readonly AddModuleLabel = new LogLabel(
|
||||||
new LogStyle().setBorder("4px", `1px solid #8600FF`)
|
"addModule",
|
||||||
.setColor("#FF00FF", "rgba(54, 0, 255, .2)").setBlank("0 5px")
|
colorRadio(54, 0, 255)
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,5 +1,13 @@
|
|||||||
import { Logger, LogLabel, LevelLogLabel, colorRadio } from "./Logger";
|
import { Logger, LogLabel, LevelLogLabel, colorRadio } from "./Logger";
|
||||||
|
|
||||||
|
interface IAppStorageParam {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* storage 缓存
|
||||||
|
*/
|
||||||
|
storage: Map<string, Storage<IStorageData>>
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 状态
|
* 状态
|
||||||
*/
|
*/
|
||||||
@ -81,7 +89,8 @@ type IStorageData = {
|
|||||||
* 1. 该类封装了 wxStorage 操作
|
* 1. 该类封装了 wxStorage 操作
|
||||||
* 2. 全异步获取无阻塞
|
* 2. 全异步获取无阻塞
|
||||||
* 3. 使用数据缓缓冲区,优化高频存取
|
* 3. 使用数据缓缓冲区,优化高频存取
|
||||||
* 4.
|
* 4. 如果全局范围内已存在莫键值 storage 的实例
|
||||||
|
* 则此实例将链接到已存在实例
|
||||||
*/
|
*/
|
||||||
class Storage<T extends IStorageData> {
|
class Storage<T extends IStorageData> {
|
||||||
|
|
||||||
@ -103,18 +112,41 @@ class Storage<T extends IStorageData> {
|
|||||||
/**
|
/**
|
||||||
* 缓存数据
|
* 缓存数据
|
||||||
*/
|
*/
|
||||||
private cache:T;
|
private _cache: T = {} as T;
|
||||||
|
private set cache(data: T) {
|
||||||
|
if (this.cacheStorage) {
|
||||||
|
for (const key in data) {
|
||||||
|
this.cacheStorage.cache[key] = data[key];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (const key in data) {
|
||||||
|
this._cache[key] = data[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private get cache():T {
|
||||||
|
if (this.cacheStorage) return this.cacheStorage.cache;
|
||||||
|
else return this._cache;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cache 到 storage 等待列表
|
* cache 到 storage 等待列表
|
||||||
*/
|
*/
|
||||||
private saveWaiter:Waiter = new Waiter();
|
private saveWaiter:Waiter = new Waiter();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 缓存对象
|
||||||
|
*/
|
||||||
|
private cacheStorage:Storage<T> | undefined;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将数据从 cache 同步到 storage
|
* 将数据从 cache 同步到 storage
|
||||||
*/
|
*/
|
||||||
public async save():Promise<void> {
|
public async save():Promise<void> {
|
||||||
|
|
||||||
|
// 如果存在链接的实例
|
||||||
|
if (this.cacheStorage) return this.cacheStorage.save();
|
||||||
|
|
||||||
// 如果没有开始存储
|
// 如果没有开始存储
|
||||||
// 发起一次异步读取
|
// 发起一次异步读取
|
||||||
if(this.saveWaiter.state === StorageState.DONE)
|
if(this.saveWaiter.state === StorageState.DONE)
|
||||||
@ -150,6 +182,24 @@ class Storage<T extends IStorageData> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在缓存中搜索此键值的实例
|
||||||
|
*/
|
||||||
|
private findStorageCache(): boolean {
|
||||||
|
let { storage: storageMap } = getApp<IAppStorageParam>();
|
||||||
|
|
||||||
|
// 查找缓存
|
||||||
|
let storage = storageMap.get(this.key);
|
||||||
|
if (storage) {
|
||||||
|
this.cacheStorage = storage as Storage<T>;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 缓存此实例
|
||||||
|
storageMap.set(this.key, this);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 重置全部数据
|
* 重置全部数据
|
||||||
*/
|
*/
|
||||||
@ -164,13 +214,25 @@ class Storage<T extends IStorageData> {
|
|||||||
/**
|
/**
|
||||||
* @param defaultData 键值默认数据
|
* @param defaultData 键值默认数据
|
||||||
*/
|
*/
|
||||||
public constructor(key:string, defaultData:T) {
|
public constructor(key:string, defaultData?:T) {
|
||||||
this.key = key;
|
this.key = key;
|
||||||
this.defaultData = defaultData;
|
this.defaultData = defaultData ?? {} as T;
|
||||||
this.StorageLogLabel = new LogLabel(
|
this.StorageLogLabel = new LogLabel(
|
||||||
`Storage:${ this.key }`, colorRadio(34, 230, 258)
|
`Storage:${ this.key }`, colorRadio(34, 230, 258)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 如果已找到其他实力,将此实例链接到目标实例
|
||||||
|
if (this.findStorageCache()) {
|
||||||
|
|
||||||
|
// 设置默认值
|
||||||
|
for (const key in this.defaultData) {
|
||||||
|
if (this.cache[key] === void 0) {
|
||||||
|
this.set(key, this.defaultData[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
// 读取数据到缓存
|
// 读取数据到缓存
|
||||||
this.cache = wx.getStorageSync<T>(this.key);
|
this.cache = wx.getStorageSync<T>(this.key);
|
||||||
|
|
||||||
@ -205,4 +267,4 @@ class Storage<T extends IStorageData> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default Storage;
|
export default Storage;
|
||||||
export { Storage, StorageState, Waiter };
|
export { Storage, StorageState, Waiter, IAppStorageParam, IStorageData };
|
@ -1,205 +0,0 @@
|
|||||||
// import { Logger } from "../logger/Logger";
|
|
||||||
import { LogStyle, LogLabel } from "./Logger";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测试结果
|
|
||||||
*/
|
|
||||||
class TestResult {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用例名称
|
|
||||||
*/
|
|
||||||
public caseName:string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测试结果
|
|
||||||
*/
|
|
||||||
public result:boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 消息
|
|
||||||
*/
|
|
||||||
public message:string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 附加消息
|
|
||||||
*/
|
|
||||||
public attach:string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 初始化
|
|
||||||
* @param caseName 用例名称
|
|
||||||
*/
|
|
||||||
constructor(caseName:string) {
|
|
||||||
this.caseName = caseName;
|
|
||||||
this.result = false;
|
|
||||||
this.message = "";
|
|
||||||
this.attach = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置结果
|
|
||||||
*/
|
|
||||||
public setResult(result:boolean, message?:string, attach?:string) {
|
|
||||||
this.result = result;
|
|
||||||
this.message = message ?? (result ? "success!" : "failed!");
|
|
||||||
this.attach = attach ?? this.attach;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测试函数结构
|
|
||||||
*/
|
|
||||||
type TestFunction = () => TestResult | Promise<TestResult>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 收集测试函数结构
|
|
||||||
*/
|
|
||||||
class CaseCollect {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用例键名
|
|
||||||
*/
|
|
||||||
public key:string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用例测试函数
|
|
||||||
*/
|
|
||||||
public caseFunction:TestFunction;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测试结果
|
|
||||||
*/
|
|
||||||
result: Promise<TestResult> | undefined;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param key 测试用例键名
|
|
||||||
* @param caseFunction 测试函数
|
|
||||||
*/
|
|
||||||
public constructor(key:string, caseFunction:TestFunction) {
|
|
||||||
this.key = key;
|
|
||||||
this.caseFunction = caseFunction;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 运行测试用例
|
|
||||||
*/
|
|
||||||
public async runTestCase():Promise<CaseCollect> {
|
|
||||||
|
|
||||||
let result = this.caseFunction();
|
|
||||||
|
|
||||||
if(result instanceof Promise) {
|
|
||||||
this.result = result;
|
|
||||||
} else {
|
|
||||||
this.result = Promise.resolve(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static readonly baseStyle = new LogStyle().setBlank();
|
|
||||||
|
|
||||||
public static readonly successLabel:LogLabel = new LogLabel("√",
|
|
||||||
new LogStyle().setBlank("0 4px").setBorder("1000px", "1px solid green")
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 打印结果
|
|
||||||
* @param current 当前进度
|
|
||||||
* @param total 总进度
|
|
||||||
*/
|
|
||||||
public printResult(current?:number, total?:number) {
|
|
||||||
|
|
||||||
// 如果测试没有运行,先运行它
|
|
||||||
if(this.result === void 0) this.runTestCase();
|
|
||||||
|
|
||||||
this.result?.then((res) => {
|
|
||||||
|
|
||||||
if(res.result) {
|
|
||||||
console.log(
|
|
||||||
`%c√%c %c1/1%c %c${ this.key }%c ` + res.message,
|
|
||||||
"padding:0 4px; border-radius:1000px; border:1px solid green; color:green",
|
|
||||||
"", "padding:0 4px; border-radius:4px; border:1px solid green; color:green",
|
|
||||||
"", "padding:0 4px; border-radius:4px; border:1px solid #979797; color:#979797",
|
|
||||||
""
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
console.log(
|
|
||||||
`%c√%c %c1/1%c %c${ this.key }%c ` + res.message,
|
|
||||||
"padding:0 4px; border-radius:1000px; border:1px solid red; color:red",
|
|
||||||
"", "padding:0 4px; border-radius:4px; border:1px solid red; color:red",
|
|
||||||
"", "padding:0 4px; border-radius:4px; border:1px solid #979797; color:#979797",
|
|
||||||
""
|
|
||||||
)
|
|
||||||
}
|
|
||||||
console.log(res)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 收集测试用例
|
|
||||||
* @param testCaseClass 测试用例表
|
|
||||||
*/
|
|
||||||
public static collectCase(testCaseClass:ITestCase):CaseCollect[] {
|
|
||||||
|
|
||||||
// 获取静态方法 key
|
|
||||||
let key = Object.getOwnPropertyNames(testCaseClass);
|
|
||||||
|
|
||||||
// 过滤掉通用的方法和属性
|
|
||||||
key = key.filter((key) => !/(length|name|prototype)/.test(key) );
|
|
||||||
|
|
||||||
// 生成 CaseCollect
|
|
||||||
let caseCollect = [];
|
|
||||||
|
|
||||||
for (let i = 0; i < key.length; i++) {
|
|
||||||
caseCollect.push(new CaseCollect(key[i], testCaseClass[key[i]]))
|
|
||||||
}
|
|
||||||
|
|
||||||
return caseCollect;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 运行测试样例
|
|
||||||
*/
|
|
||||||
public static async runCollectCase(cases:CaseCollect[]):Promise<CaseCollect[]> {
|
|
||||||
|
|
||||||
let running:Promise<CaseCollect>[] = [];
|
|
||||||
|
|
||||||
for(let i = 0; i < cases.length; i++) {
|
|
||||||
running.push(cases[i].runTestCase());
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.all(running);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 启动单元测试
|
|
||||||
*/
|
|
||||||
public static runUnitTest(testCaseClass:ITestCase) {
|
|
||||||
|
|
||||||
let caseCollect = this.collectCase(testCaseClass);
|
|
||||||
|
|
||||||
CaseCollect.runCollectCase(caseCollect).then((caseCollect:CaseCollect[]) => {
|
|
||||||
|
|
||||||
for(let i = 0; i < caseCollect.length; i++) {
|
|
||||||
caseCollect[i].printResult()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测试用例接口
|
|
||||||
*/
|
|
||||||
interface ITestCase {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测试用例函数
|
|
||||||
*/
|
|
||||||
[key:string]:TestFunction;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ITestCase;
|
|
||||||
export { ITestCase, TestResult, TestFunction, CaseCollect };
|
|
@ -4,7 +4,7 @@ import { Logger, LogLabel, LevelLogLabel, LifeCycleLogLabel, NormalStyle } from
|
|||||||
/**
|
/**
|
||||||
* 在 UI 中显示的数据
|
* 在 UI 中显示的数据
|
||||||
*/
|
*/
|
||||||
type DisplayData = {
|
interface IDisplayData {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 显示内容
|
* 显示内容
|
||||||
@ -20,8 +20,8 @@ type DisplayData = {
|
|||||||
/**
|
/**
|
||||||
* 模组事件
|
* 模组事件
|
||||||
*/
|
*/
|
||||||
type StatusBarEvent = {
|
interface StatusBarEvent {
|
||||||
m: DisplayData
|
m: IDisplayData
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -8,13 +8,22 @@ import { Storage } from "../../core/Storage";
|
|||||||
class TestCore<M extends Manager> extends Modular<M>
|
class TestCore<M extends Manager> extends Modular<M>
|
||||||
implements Partial<ILifetime> {
|
implements Partial<ILifetime> {
|
||||||
|
|
||||||
public onLoad() {
|
public override onLoad() {
|
||||||
|
|
||||||
let s = new Storage("test", {
|
let s = new Storage("test", {
|
||||||
a: new Date(),
|
a: new Date(),
|
||||||
be: 2
|
be: 2
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let s2 = new Storage("test", {
|
||||||
|
be: 1,
|
||||||
|
aa: "abc"
|
||||||
|
});
|
||||||
|
|
||||||
|
s2.set("be", 4);
|
||||||
|
|
||||||
|
console.log(s, s2);
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
s.set("be", 12);
|
s.set("be", 12);
|
||||||
}, 1000)
|
}, 1000)
|
||||||
@ -55,9 +64,7 @@ implements Partial<ILifetime> {
|
|||||||
}
|
}
|
||||||
}).request().wait({
|
}).request().wait({
|
||||||
success: (d) => console.log(d)
|
success: (d) => console.log(d)
|
||||||
}).wait({
|
})
|
||||||
success: (d) => console.log(d)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user