mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2025-05-08 11:39:05 +08:00
fix(core): 事件触发时组件未初始化,等组件初始化后再调用事件处理
This commit is contained in:
parent
a4abf5feea
commit
1750467d5b
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
|
|
||||||
import type { Id, MApp } from '@tmagic/schema';
|
import type { EventItemConfig, Id, MApp } from '@tmagic/schema';
|
||||||
|
|
||||||
import Env from './Env';
|
import Env from './Env';
|
||||||
import {
|
import {
|
||||||
@ -40,17 +40,25 @@ interface AppOptionsConfig {
|
|||||||
transformStyle?: (style: Record<string, any>) => Record<string, any>;
|
transformStyle?: (style: Record<string, any>) => Record<string, any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface EventCache {
|
||||||
|
eventConfig: EventItemConfig;
|
||||||
|
fromCpt: any;
|
||||||
|
args: any[];
|
||||||
|
}
|
||||||
|
|
||||||
class App extends EventEmitter {
|
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';
|
public platform = 'mobile';
|
||||||
jsEngine = 'browser';
|
public jsEngine = 'browser';
|
||||||
|
|
||||||
components = new Map();
|
public components = new Map();
|
||||||
|
|
||||||
|
public eventQueueMap: Record<string, EventCache[]> = {};
|
||||||
|
|
||||||
constructor(options: AppOptionsConfig) {
|
constructor(options: AppOptionsConfig) {
|
||||||
super();
|
super();
|
||||||
@ -89,7 +97,7 @@ class App extends EventEmitter {
|
|||||||
* @param style Object
|
* @param style Object
|
||||||
* @returns Object
|
* @returns Object
|
||||||
*/
|
*/
|
||||||
transformStyle(style: Record<string, any> | string) {
|
public transformStyle(style: Record<string, any> | string) {
|
||||||
if (!style) {
|
if (!style) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -132,7 +140,7 @@ class App extends EventEmitter {
|
|||||||
* @param config dsl跟节点
|
* @param config dsl跟节点
|
||||||
* @param curPage 当前页面id
|
* @param curPage 当前页面id
|
||||||
*/
|
*/
|
||||||
setConfig(config: MApp, curPage?: Id) {
|
public setConfig(config: MApp, curPage?: Id) {
|
||||||
this.pages = new Map();
|
this.pages = new Map();
|
||||||
|
|
||||||
config.items?.forEach((page) => {
|
config.items?.forEach((page) => {
|
||||||
@ -140,6 +148,7 @@ class App extends EventEmitter {
|
|||||||
page.id,
|
page.id,
|
||||||
new Page({
|
new Page({
|
||||||
config: page,
|
config: page,
|
||||||
|
app: this,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -147,7 +156,7 @@ class App extends EventEmitter {
|
|||||||
this.setPage(curPage || this.page?.data?.id);
|
this.setPage(curPage || this.page?.data?.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
setPage(id?: Id) {
|
public setPage(id?: Id) {
|
||||||
let page;
|
let page;
|
||||||
|
|
||||||
if (id) {
|
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);
|
this.components.set(type, Component);
|
||||||
}
|
}
|
||||||
|
|
||||||
unregisterComponent(type: string) {
|
public unregisterComponent(type: string) {
|
||||||
this.components.delete(type);
|
this.components.delete(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
resolveComponent(type: string) {
|
public resolveComponent(type: string) {
|
||||||
return this.components.get(type);
|
return this.components.get(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
bindEvents() {
|
public bindEvents() {
|
||||||
if (!this.page) return;
|
if (!this.page) return;
|
||||||
|
|
||||||
this.removeAllListeners();
|
this.removeAllListeners();
|
||||||
|
|
||||||
for (const [, value] of this.page.nodes) {
|
for (const [, value] of this.page.nodes) {
|
||||||
value.events?.forEach((event) => {
|
value.events?.forEach((event) => this.bindEvent(event, `${value.data.id}`));
|
||||||
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) => {
|
public bindEvent(event: EventItemConfig, id: string) {
|
||||||
if (!this.page) throw new Error('当前没有页面');
|
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);
|
this.on(eventName, (fromCpt, ...args) => {
|
||||||
if (!toNode) throw `ID为${event.to}的组件不存在`;
|
this.eventHandler(event, fromCpt, args);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const { method: methodName } = event;
|
public eventHandler(eventConfig: EventItemConfig, fromCpt: any, args: any[]) {
|
||||||
if (isCommonMethod(methodName)) {
|
if (!this.page) throw new Error('当前没有页面');
|
||||||
return triggerCommonMethod(methodName, toNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof toNode.instance?.[methodName] === 'function') {
|
const { method: methodName, to } = eventConfig;
|
||||||
toNode.instance[methodName](fromCpt, ...args);
|
|
||||||
}
|
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.removeAllListeners();
|
||||||
this.pages.clear();
|
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;
|
export default App;
|
||||||
|
@ -20,19 +20,34 @@ import { EventEmitter } from 'events';
|
|||||||
|
|
||||||
import type { EventItemConfig, MComponent, MContainer, MPage } from '@tmagic/schema';
|
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 {
|
class Node extends EventEmitter {
|
||||||
data: MComponent | MContainer | MPage;
|
public data: MComponent | MContainer | MPage;
|
||||||
style?: {
|
public style?: {
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
};
|
};
|
||||||
events?: EventItemConfig[];
|
public events?: EventItemConfig[];
|
||||||
instance?: any;
|
public instance?: any;
|
||||||
|
public page?: Page;
|
||||||
|
public parent?: Node;
|
||||||
|
public app: App;
|
||||||
|
|
||||||
constructor(config: MComponent | MContainer) {
|
constructor(options: NodeOptions) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
const { events } = config;
|
this.page = options.page;
|
||||||
this.data = config;
|
this.parent = options.parent;
|
||||||
|
this.app = options.app;
|
||||||
|
const { events } = options.config;
|
||||||
|
this.data = options.config;
|
||||||
this.events = events;
|
this.events = events;
|
||||||
|
|
||||||
this.listenLifeSafe();
|
this.listenLifeSafe();
|
||||||
@ -47,9 +62,10 @@ class Node extends EventEmitter {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
listenLifeSafe() {
|
private listenLifeSafe() {
|
||||||
this.once('created', (instance: any) => {
|
this.once('created', (instance: any) => {
|
||||||
this.instance = instance;
|
this.instance = instance;
|
||||||
|
|
||||||
if (typeof this.data.created === 'function') {
|
if (typeof this.data.created === 'function') {
|
||||||
this.data.created(this);
|
this.data.created(this);
|
||||||
}
|
}
|
||||||
@ -57,6 +73,13 @@ class Node extends EventEmitter {
|
|||||||
|
|
||||||
this.once('mounted', (instance: any) => {
|
this.once('mounted', (instance: any) => {
|
||||||
this.instance = instance;
|
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') {
|
if (typeof this.data.mounted === 'function') {
|
||||||
this.data.mounted(this);
|
this.data.mounted(this);
|
||||||
}
|
}
|
||||||
|
@ -18,38 +18,47 @@
|
|||||||
|
|
||||||
import type { Id, MComponent, MContainer, MPage } from '@tmagic/schema';
|
import type { Id, MComponent, MContainer, MPage } from '@tmagic/schema';
|
||||||
|
|
||||||
|
import type App from './App';
|
||||||
import Node from './Node';
|
import Node from './Node';
|
||||||
interface ConfigOptions {
|
interface ConfigOptions {
|
||||||
config: MPage;
|
config: MPage;
|
||||||
|
app: App;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Page extends Node {
|
class Page extends Node {
|
||||||
nodes = new Map<Id, Node>();
|
public nodes = new Map<Id, Node>();
|
||||||
|
|
||||||
constructor(options: ConfigOptions) {
|
constructor(options: ConfigOptions) {
|
||||||
super(options.config);
|
super(options);
|
||||||
|
|
||||||
this.setNode(options.config.id, this);
|
this.setNode(options.config.id, this);
|
||||||
this.initNode(options.config);
|
this.initNode(options.config, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
initNode(config: MComponent | MContainer) {
|
public initNode(config: MComponent | MContainer, parent: Node) {
|
||||||
this.setNode(config.id, new Node(config));
|
const node = new Node({
|
||||||
|
config,
|
||||||
|
parent,
|
||||||
|
page: this,
|
||||||
|
app: this.app,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.setNode(config.id, node);
|
||||||
|
|
||||||
config.items?.forEach((element: MComponent | MContainer) => {
|
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);
|
return this.nodes.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
setNode(id: Id, node: Node) {
|
public setNode(id: Id, node: Node) {
|
||||||
this.nodes.set(id, node);
|
this.nodes.set(id, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteNode(id: Id) {
|
public deleteNode(id: Id) {
|
||||||
this.nodes.delete(id);
|
this.nodes.delete(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user