mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2025-04-06 03:57:56 +08:00
fix(core): 事件触发时组件未初始化,等组件初始化后再调用事件处理
This commit is contained in:
parent
a4abf5feea
commit
1750467d5b
@ -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 {
|
||||
@ -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;
|
||||
|
||||
pages = new Map<Id, Page>();
|
||||
public pages = new Map<Id, Page>();
|
||||
|
||||
page: Page | undefined;
|
||||
public page: Page | undefined;
|
||||
|
||||
platform = 'mobile';
|
||||
jsEngine = 'browser';
|
||||
public platform = 'mobile';
|
||||
public jsEngine = 'browser';
|
||||
|
||||
components = new Map();
|
||||
public components = new Map();
|
||||
|
||||
public eventQueueMap: Record<string, EventCache[]> = {};
|
||||
|
||||
constructor(options: AppOptionsConfig) {
|
||||
super();
|
||||
@ -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 {};
|
||||
}
|
||||
@ -132,7 +140,7 @@ 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) => {
|
||||
@ -140,6 +148,7 @@ class App extends EventEmitter {
|
||||
page.id,
|
||||
new Page({
|
||||
config: page,
|
||||
app: this,
|
||||
}),
|
||||
);
|
||||
});
|
||||
@ -147,7 +156,7 @@ class App extends EventEmitter {
|
||||
this.setPage(curPage || this.page?.data?.id);
|
||||
}
|
||||
|
||||
setPage(id?: Id) {
|
||||
public setPage(id?: Id) {
|
||||
let page;
|
||||
|
||||
if (id) {
|
||||
@ -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}`);
|
||||
}
|
||||
value.events?.forEach((event) => this.bindEvent(event, `${value.data.id}`));
|
||||
}
|
||||
}
|
||||
|
||||
this.on(eventName, (fromCpt, ...args) => {
|
||||
if (!this.page) throw new Error('当前没有页面');
|
||||
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);
|
||||
}
|
||||
|
||||
const toNode = this.page.getNode(event.to);
|
||||
if (!toNode) throw `ID为${event.to}的组件不存在`;
|
||||
this.on(eventName, (fromCpt, ...args) => {
|
||||
this.eventHandler(event, fromCpt, args);
|
||||
});
|
||||
}
|
||||
|
||||
const { method: methodName } = event;
|
||||
if (isCommonMethod(methodName)) {
|
||||
return triggerCommonMethod(methodName, toNode);
|
||||
}
|
||||
public eventHandler(eventConfig: EventItemConfig, fromCpt: any, args: any[]) {
|
||||
if (!this.page) throw new Error('当前没有页面');
|
||||
|
||||
if (typeof toNode.instance?.[methodName] === 'function') {
|
||||
toNode.instance[methodName](fromCpt, ...args);
|
||||
}
|
||||
});
|
||||
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;
|
||||
|
@ -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();
|
||||
@ -47,9 +62,10 @@ 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);
|
||||
}
|
||||
@ -57,6 +73,13 @@ class Node extends EventEmitter {
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user