Skip to content

Commit

Permalink
fix(core): 事件触发时组件未初始化,等组件初始化后再调用事件处理
Browse files Browse the repository at this point in the history
  • Loading branch information
roymondchen authored and jia000 committed Jul 19, 2022
1 parent a4abf5f commit 1750467
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 54 deletions.
106 changes: 69 additions & 37 deletions packages/core/src/App.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

import { EventEmitter } from 'events';

import type { Id, MApp } from '@tmagic/schema';
import type { EventItemConfig, Id, MApp } from '@tmagic/schema';

import Env from './Env';
import {
Expand All @@ -40,17 +40,25 @@ interface AppOptionsConfig {
transformStyle?: (style: Record<string, any>) => Record<string, any>;
}

interface EventCache {
eventConfig: EventItemConfig;
fromCpt: any;
args: any[];
}

class App extends EventEmitter {
env;
public env;

public pages = new Map<Id, Page>();

pages = new Map<Id, Page>();
public page: Page | undefined;

page: Page | undefined;
public platform = 'mobile';
public jsEngine = 'browser';

platform = 'mobile';
jsEngine = 'browser';
public components = new Map();

components = new Map();
public eventQueueMap: Record<string, EventCache[]> = {};

constructor(options: AppOptionsConfig) {
super();
Expand Down Expand Up @@ -89,7 +97,7 @@ class App extends EventEmitter {
* @param style Object
* @returns Object
*/
transformStyle(style: Record<string, any> | string) {
public transformStyle(style: Record<string, any> | string) {
if (!style) {
return {};
}
Expand Down Expand Up @@ -132,22 +140,23 @@ class App extends EventEmitter {
* @param config dsl跟节点
* @param curPage 当前页面id
*/
setConfig(config: MApp, curPage?: Id) {
public setConfig(config: MApp, curPage?: Id) {
this.pages = new Map();

config.items?.forEach((page) => {
this.pages.set(
page.id,
new Page({
config: page,
app: this,
}),
);
});

this.setPage(curPage || this.page?.data?.id);
}

setPage(id?: Id) {
public setPage(id?: Id) {
let page;

if (id) {
Expand All @@ -165,54 +174,77 @@ class App extends EventEmitter {
}
}

registerComponent(type: string, Component: any) {
public registerComponent(type: string, Component: any) {
this.components.set(type, Component);
}

unregisterComponent(type: string) {
public unregisterComponent(type: string) {
this.components.delete(type);
}

resolveComponent(type: string) {
public resolveComponent(type: string) {
return this.components.get(type);
}

bindEvents() {
public bindEvents() {
if (!this.page) return;

this.removeAllListeners();

for (const [, value] of this.page.nodes) {
value.events?.forEach((event) => {
let { name: eventName } = event;
if (DEFAULT_EVENTS.findIndex((defaultEvent) => defaultEvent.value === eventName) > -1) {
// common 事件名通过 node id 避免重复触发
eventName = getCommonEventName(eventName, `${value.data.id}`);
}

this.on(eventName, (fromCpt, ...args) => {
if (!this.page) throw new Error('当前没有页面');

const toNode = this.page.getNode(event.to);
if (!toNode) throw `ID为${event.to}的组件不存在`;

const { method: methodName } = event;
if (isCommonMethod(methodName)) {
return triggerCommonMethod(methodName, toNode);
}

if (typeof toNode.instance?.[methodName] === 'function') {
toNode.instance[methodName](fromCpt, ...args);
}
});
value.events?.forEach((event) => this.bindEvent(event, `${value.data.id}`));
}
}

public bindEvent(event: EventItemConfig, id: string) {
let { name: eventName } = event;
if (DEFAULT_EVENTS.findIndex((defaultEvent) => defaultEvent.value === eventName) > -1) {
// common 事件名通过 node id 避免重复触发
eventName = getCommonEventName(eventName, id);
}

this.on(eventName, (fromCpt, ...args) => {
this.eventHandler(event, fromCpt, args);
});
}

public eventHandler(eventConfig: EventItemConfig, fromCpt: any, args: any[]) {
if (!this.page) throw new Error('当前没有页面');

const { method: methodName, to } = eventConfig;

const toNode = this.page.getNode(to);
if (!toNode) throw `ID为${to}的组件不存在`;

if (isCommonMethod(methodName)) {
return triggerCommonMethod(methodName, toNode);
}

if (toNode.instance) {
if (typeof toNode.instance[methodName] === 'function') {
toNode.instance[methodName](fromCpt, ...args);
}
} else {
this.addEventToMap({
eventConfig,
fromCpt,
args,
});
}
}

destroy() {
public destroy() {
this.removeAllListeners();
this.pages.clear();
}

private addEventToMap(event: EventCache) {
if (this.eventQueueMap[event.eventConfig.to]) {
this.eventQueueMap[event.eventConfig.to].push(event);
} else {
this.eventQueueMap[event.eventConfig.to] = [event];
}
}
}

export default App;
39 changes: 31 additions & 8 deletions packages/core/src/Node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,34 @@ import { EventEmitter } from 'events';

import type { EventItemConfig, MComponent, MContainer, MPage } from '@tmagic/schema';

import type App from './App';
import type Page from './Page';

interface NodeOptions {
config: MComponent | MContainer;
page?: Page;
parent?: Node;
app: App;
}
class Node extends EventEmitter {
data: MComponent | MContainer | MPage;
style?: {
public data: MComponent | MContainer | MPage;
public style?: {
[key: string]: any;
};
events?: EventItemConfig[];
instance?: any;
public events?: EventItemConfig[];
public instance?: any;
public page?: Page;
public parent?: Node;
public app: App;

constructor(config: MComponent | MContainer) {
constructor(options: NodeOptions) {
super();

const { events } = config;
this.data = config;
this.page = options.page;
this.parent = options.parent;
this.app = options.app;
const { events } = options.config;
this.data = options.config;
this.events = events;

this.listenLifeSafe();
Expand All @@ -47,16 +62,24 @@ class Node extends EventEmitter {
});
}

listenLifeSafe() {
private listenLifeSafe() {
this.once('created', (instance: any) => {
this.instance = instance;

if (typeof this.data.created === 'function') {
this.data.created(this);
}
});

this.once('mounted', (instance: any) => {
this.instance = instance;

const eventConfigQueue = this.app.eventQueueMap[instance.config.id] || [];

for (let eventConfig = eventConfigQueue.shift(); eventConfig; eventConfig = eventConfigQueue.shift()) {
this.app.eventHandler(eventConfig.eventConfig, eventConfig.fromCpt, eventConfig.args);
}

if (typeof this.data.mounted === 'function') {
this.data.mounted(this);
}
Expand Down
27 changes: 18 additions & 9 deletions packages/core/src/Page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,38 +18,47 @@

import type { Id, MComponent, MContainer, MPage } from '@tmagic/schema';

import type App from './App';
import Node from './Node';
interface ConfigOptions {
config: MPage;
app: App;
}

class Page extends Node {
nodes = new Map<Id, Node>();
public nodes = new Map<Id, Node>();

constructor(options: ConfigOptions) {
super(options.config);
super(options);

this.setNode(options.config.id, this);
this.initNode(options.config);
this.initNode(options.config, this);
}

initNode(config: MComponent | MContainer) {
this.setNode(config.id, new Node(config));
public initNode(config: MComponent | MContainer, parent: Node) {
const node = new Node({
config,
parent,
page: this,
app: this.app,
});

this.setNode(config.id, node);

config.items?.forEach((element: MComponent | MContainer) => {
this.initNode(element);
this.initNode(element, node);
});
}

getNode(id: Id) {
public getNode(id: Id) {
return this.nodes.get(id);
}

setNode(id: Id, node: Node) {
public setNode(id: Id, node: Node) {
this.nodes.set(id, node);
}

deleteNode(id: Id) {
public deleteNode(id: Id) {
this.nodes.delete(id);
}
}
Expand Down

0 comments on commit 1750467

Please sign in to comment.