mirror of
https://gitee.com/baidu/amis.git
synced 2024-12-02 03:58:07 +08:00
fix:修复事件动作可能导致循环依赖问题 (#4083)
This commit is contained in:
parent
d1d1eddf5d
commit
0a1d1a10d2
@ -20,7 +20,7 @@ import getExprProperties from './utils/filter-schema';
|
||||
import {anyChanged, chainEvents, autobind} from './utils/helper';
|
||||
import {SimpleMap} from './utils/SimpleMap';
|
||||
|
||||
import type {RendererEvent} from './utils/renderer-event';
|
||||
import {bindEvent, dispatchEvent, RendererEvent} from './utils/renderer-event';
|
||||
import {isAlive} from 'mobx-state-tree';
|
||||
import {reaction} from 'mobx';
|
||||
import {resolveVariableAndFilter} from './utils/tpl-builtin';
|
||||
@ -93,9 +93,8 @@ export class SchemaRenderer extends React.Component<SchemaRendererProps, any> {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const {env} = this.props;
|
||||
// 这里无法区分监听的是不是广播,所以又bind一下,主要是为了绑广播
|
||||
this.unbindEvent = env.bindEvent(this.cRef);
|
||||
this.unbindEvent = bindEvent(this.cRef);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
@ -206,8 +205,8 @@ export class SchemaRenderer extends React.Component<SchemaRendererProps, any> {
|
||||
async dispatchEvent(
|
||||
e: React.MouseEvent<any>,
|
||||
data: any
|
||||
): Promise<RendererEvent<any> | undefined> {
|
||||
return await this.props.env.dispatchEvent(e, this.cRef, this.context, data);
|
||||
): Promise<RendererEvent<any> | void> {
|
||||
return await dispatchEvent(e, this.cRef, this.context, data);
|
||||
}
|
||||
|
||||
renderChild(
|
||||
|
@ -1,3 +1,4 @@
|
||||
import {RendererProps} from '../factory';
|
||||
import {extendObject} from '../utils/helper';
|
||||
import {RendererEvent} from '../utils/renderer-event';
|
||||
import {evalExpression} from '../utils/tpl';
|
||||
@ -29,26 +30,26 @@ export interface LogicAction extends ListenerAction {
|
||||
children?: ListenerAction[]; // 子动作
|
||||
}
|
||||
|
||||
export interface ListenerContext {
|
||||
export interface ListenerContext extends React.Component<RendererProps> {
|
||||
[propName: string]: any;
|
||||
}
|
||||
|
||||
// Action 基础接口
|
||||
export interface Action {
|
||||
export interface RendererAction {
|
||||
// 运行这个 Action,每个类型的 Action 都只有一个实例,run 函数是个可重入的函数
|
||||
run: (
|
||||
action: ListenerAction,
|
||||
renderer: ListenerContext,
|
||||
event: RendererEvent<any>,
|
||||
mergeData?: any // 有些Action内部需要通过上下文数据处理专有逻辑,这里的数据是事件数据+渲染器数据
|
||||
) => Promise<void>;
|
||||
) => Promise<RendererEvent<any> | void>;
|
||||
}
|
||||
|
||||
// 存储 Action 和类型的映射关系,用于后续查找
|
||||
const ActionTypeMap: {[key: string]: Action} = {};
|
||||
const ActionTypeMap: {[key: string]: RendererAction} = {};
|
||||
|
||||
// 注册 Action
|
||||
export const registerAction = (type: string, action: Action) => {
|
||||
export const registerAction = (type: string, action: RendererAction) => {
|
||||
ActionTypeMap[type] = action;
|
||||
};
|
||||
|
||||
@ -97,7 +98,7 @@ export const runActions = async (
|
||||
|
||||
// 执行动作,与原有动作处理打通
|
||||
export const runAction = async (
|
||||
actionInstrance: Action,
|
||||
actionInstrance: RendererAction,
|
||||
actionConfig: ListenerAction,
|
||||
renderer: ListenerContext,
|
||||
event: any
|
||||
|
@ -5,7 +5,7 @@ import {createObject, isEmpty, isVisible} from '../utils/helper';
|
||||
import {RendererEvent} from '../utils/renderer-event';
|
||||
import {filter} from '../utils/tpl';
|
||||
import {
|
||||
Action,
|
||||
RendererAction,
|
||||
ListenerAction,
|
||||
ListenerContext,
|
||||
registerAction
|
||||
@ -27,7 +27,7 @@ export interface IAjaxAction extends ListenerAction {
|
||||
* @class AjaxAction
|
||||
* @implements {Action}
|
||||
*/
|
||||
export class AjaxAction implements Action {
|
||||
export class AjaxAction implements RendererAction {
|
||||
async run(
|
||||
action: IAjaxAction,
|
||||
renderer: ListenerContext,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {RendererEvent} from '../utils/renderer-event';
|
||||
import {
|
||||
Action,
|
||||
RendererAction,
|
||||
ListenerAction,
|
||||
ListenerContext,
|
||||
LoopStatus,
|
||||
@ -14,7 +14,7 @@ import {
|
||||
* @class BreakAction
|
||||
* @implements {Action}
|
||||
*/
|
||||
export class BreakAction implements Action {
|
||||
export class BreakAction implements RendererAction {
|
||||
async run(
|
||||
action: ListenerAction,
|
||||
renderer: ListenerContext,
|
||||
|
@ -1,7 +1,8 @@
|
||||
import {RendererProps} from '../factory';
|
||||
import {createObject} from '../utils/helper';
|
||||
import {RendererEvent} from '../utils/renderer-event';
|
||||
import {RendererEvent, dispatchEvent} from '../utils/renderer-event';
|
||||
import {
|
||||
Action,
|
||||
RendererAction,
|
||||
ListenerAction,
|
||||
ListenerContext,
|
||||
registerAction
|
||||
@ -18,7 +19,7 @@ export interface IBroadcastAction extends ListenerAction {
|
||||
* @class BroadcastAction
|
||||
* @implements {Action}
|
||||
*/
|
||||
export class BroadcastAction implements Action {
|
||||
export class BroadcastAction implements RendererAction {
|
||||
async run(
|
||||
action: IBroadcastAction,
|
||||
renderer: ListenerContext,
|
||||
@ -33,7 +34,7 @@ export class BroadcastAction implements Action {
|
||||
event.setData(createObject(event.data, action.args));
|
||||
|
||||
// 直接触发对应的动作
|
||||
return await event.context.env.dispatchEvent(
|
||||
return await dispatchEvent(
|
||||
action.eventName,
|
||||
renderer,
|
||||
event.context.scoped,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import {RendererEvent} from '../utils/renderer-event';
|
||||
import {dataMapping} from '../utils/tpl-builtin';
|
||||
import {
|
||||
Action,
|
||||
RendererAction,
|
||||
ListenerAction,
|
||||
ListenerContext,
|
||||
LoopStatus,
|
||||
@ -19,7 +19,7 @@ export interface ICmptAction extends ListenerAction {
|
||||
* @class CmptAction
|
||||
* @implements {Action}
|
||||
*/
|
||||
export class CmptAction implements Action {
|
||||
export class CmptAction implements RendererAction {
|
||||
async run(
|
||||
action: ICmptAction,
|
||||
renderer: ListenerContext,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {RendererEvent} from '../utils/renderer-event';
|
||||
import {
|
||||
Action,
|
||||
RendererAction,
|
||||
ListenerAction,
|
||||
ListenerContext,
|
||||
LoopStatus,
|
||||
@ -14,7 +14,7 @@ import {
|
||||
* @class ContinueAction
|
||||
* @implements {Action}
|
||||
*/
|
||||
export class ContinueAction implements Action {
|
||||
export class ContinueAction implements RendererAction {
|
||||
async run(
|
||||
action: ListenerAction,
|
||||
renderer: ListenerContext,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import {RendererEvent} from '../utils/renderer-event';
|
||||
import {filter} from '../utils/tpl';
|
||||
import {
|
||||
Action,
|
||||
RendererAction,
|
||||
ListenerAction,
|
||||
ListenerContext,
|
||||
LoopStatus,
|
||||
@ -20,7 +20,7 @@ export interface ICopyAction extends ListenerAction {
|
||||
* @class CopyAction
|
||||
* @implements {Action}
|
||||
*/
|
||||
export class CopyAction implements Action {
|
||||
export class CopyAction implements RendererAction {
|
||||
async run(
|
||||
action: ICopyAction,
|
||||
renderer: ListenerContext,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {RendererEvent} from '../utils/renderer-event';
|
||||
import {
|
||||
Action,
|
||||
RendererAction,
|
||||
ListenerAction,
|
||||
ListenerContext,
|
||||
LoopStatus,
|
||||
@ -18,7 +18,7 @@ export interface ICustomAction extends ListenerAction {
|
||||
* @class CustomAction
|
||||
* @implements {Action}
|
||||
*/
|
||||
export class CustomAction implements Action {
|
||||
export class CustomAction implements RendererAction {
|
||||
async run(
|
||||
action: ICustomAction,
|
||||
renderer: ListenerContext,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import {SchemaNode} from '../types';
|
||||
import {RendererEvent} from '../utils/renderer-event';
|
||||
import {
|
||||
Action,
|
||||
RendererAction,
|
||||
ListenerAction,
|
||||
ListenerContext,
|
||||
registerAction
|
||||
@ -27,7 +27,7 @@ export interface IDialogAction extends ListenerAction {
|
||||
* @class DialogAction
|
||||
* @implements {Action}
|
||||
*/
|
||||
export class DialogAction implements Action {
|
||||
export class DialogAction implements RendererAction {
|
||||
async run(
|
||||
action: IDialogAction,
|
||||
renderer: ListenerContext,
|
||||
@ -44,7 +44,7 @@ export class DialogAction implements Action {
|
||||
* @class CloseDialogAction
|
||||
* @implements {Action}
|
||||
*/
|
||||
export class CloseDialogAction implements Action {
|
||||
export class CloseDialogAction implements RendererAction {
|
||||
async run(
|
||||
action: ListenerAction,
|
||||
renderer: ListenerContext,
|
||||
@ -70,7 +70,7 @@ export class CloseDialogAction implements Action {
|
||||
/**
|
||||
* alert提示动作
|
||||
*/
|
||||
export class AlertAction implements Action {
|
||||
export class AlertAction implements RendererAction {
|
||||
async run(
|
||||
action: IAlertAction,
|
||||
renderer: ListenerContext,
|
||||
@ -83,7 +83,7 @@ export class AlertAction implements Action {
|
||||
/**
|
||||
* confirm确认提示动作
|
||||
*/
|
||||
export class ConfirmAction implements Action {
|
||||
export class ConfirmAction implements RendererAction {
|
||||
async run(
|
||||
action: IConfirmAction,
|
||||
renderer: ListenerContext,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import {SchemaNode} from '../types';
|
||||
import {RendererEvent} from '../utils/renderer-event';
|
||||
import {
|
||||
Action,
|
||||
RendererAction,
|
||||
ListenerAction,
|
||||
ListenerContext,
|
||||
registerAction
|
||||
@ -18,7 +18,7 @@ export interface IDrawerAction extends ListenerAction {
|
||||
* @class DrawerAction
|
||||
* @implements {Action}
|
||||
*/
|
||||
export class DrawerAction implements Action {
|
||||
export class DrawerAction implements RendererAction {
|
||||
async run(
|
||||
action: IDrawerAction,
|
||||
renderer: ListenerContext,
|
||||
@ -35,7 +35,7 @@ export class DrawerAction implements Action {
|
||||
* @class CloseDrawerAction
|
||||
* @implements {Action}
|
||||
*/
|
||||
export class CloseDrawerAction implements Action {
|
||||
export class CloseDrawerAction implements RendererAction {
|
||||
async run(
|
||||
action: ListenerAction,
|
||||
renderer: ListenerContext,
|
||||
|
@ -4,7 +4,7 @@ import pick from 'lodash/pick';
|
||||
import mapValues from 'lodash/mapValues';
|
||||
import qs from 'qs';
|
||||
import {
|
||||
Action,
|
||||
RendererAction,
|
||||
ListenerAction,
|
||||
ListenerContext,
|
||||
registerAction
|
||||
@ -25,7 +25,7 @@ export interface IEmailAction extends ListenerAction {
|
||||
* @class EmailAction
|
||||
* @implements {Action}
|
||||
*/
|
||||
export class EmailAction implements Action {
|
||||
export class EmailAction implements RendererAction {
|
||||
async run(
|
||||
action: IEmailAction,
|
||||
renderer: ListenerContext,
|
||||
|
@ -1,9 +1,10 @@
|
||||
import {Action} from '../types';
|
||||
import {buildApi} from '../utils/api';
|
||||
import {isEmpty, isObject, qsstringify} from '../utils/helper';
|
||||
import {RendererEvent} from '../utils/renderer-event';
|
||||
import {filter} from '../utils/tpl';
|
||||
import {
|
||||
Action,
|
||||
RendererAction,
|
||||
ListenerAction,
|
||||
ListenerContext,
|
||||
registerAction
|
||||
@ -12,6 +13,7 @@ import {
|
||||
export interface ILinkAction extends ListenerAction {
|
||||
link: string;
|
||||
url?: never;
|
||||
blank?: boolean;
|
||||
params?: {
|
||||
[key: string]: string;
|
||||
};
|
||||
@ -20,6 +22,7 @@ export interface ILinkAction extends ListenerAction {
|
||||
export interface IUrlAction extends ListenerAction {
|
||||
url: string;
|
||||
link?: never;
|
||||
blank?: boolean;
|
||||
params?: {
|
||||
[key: string]: string;
|
||||
};
|
||||
@ -32,7 +35,7 @@ export interface IUrlAction extends ListenerAction {
|
||||
* @class LinkAction
|
||||
* @implements {Action}
|
||||
*/
|
||||
export class LinkAction implements Action {
|
||||
export class LinkAction implements RendererAction {
|
||||
async run(
|
||||
action: ILinkAction | IUrlAction,
|
||||
renderer: ListenerContext,
|
||||
@ -54,7 +57,7 @@ export class LinkAction implements Action {
|
||||
}
|
||||
);
|
||||
|
||||
renderer.props.env.jumpTo(urlObj.url, action, action.args);
|
||||
renderer.props.env.jumpTo(urlObj.url, action as Action, action.args);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import {RendererEvent} from '../utils/renderer-event';
|
||||
import {createObject} from '../utils/helper';
|
||||
import {
|
||||
Action,
|
||||
RendererAction,
|
||||
ListenerAction,
|
||||
ListenerContext,
|
||||
LogicAction,
|
||||
@ -23,7 +23,7 @@ export interface ILoopAction extends ListenerAction, LogicAction {
|
||||
* @class LoopAction
|
||||
* @implements {Action}
|
||||
*/
|
||||
export class LoopAction implements Action {
|
||||
export class LoopAction implements RendererAction {
|
||||
async run(
|
||||
action: ILoopAction,
|
||||
renderer: ListenerContext,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {RendererEvent} from '../utils/renderer-event';
|
||||
import {
|
||||
Action,
|
||||
RendererAction,
|
||||
ListenerAction,
|
||||
ListenerContext,
|
||||
registerAction
|
||||
@ -17,7 +17,7 @@ export interface IPageGoAction extends ListenerAction {
|
||||
* @class PageGoBackAction
|
||||
* @implements {Action}
|
||||
*/
|
||||
export class PageGoBackAction implements Action {
|
||||
export class PageGoBackAction implements RendererAction {
|
||||
async run(
|
||||
action: ListenerAction,
|
||||
renderer: ListenerContext,
|
||||
@ -34,7 +34,7 @@ export class PageGoBackAction implements Action {
|
||||
* @class PageGoAction
|
||||
* @implements {Action}
|
||||
*/
|
||||
export class PageGoAction implements Action {
|
||||
export class PageGoAction implements RendererAction {
|
||||
async run(
|
||||
action: IPageGoAction,
|
||||
renderer: ListenerContext,
|
||||
@ -51,7 +51,7 @@ export class PageGoAction implements Action {
|
||||
* @class PageRefreshAction
|
||||
* @implements {Action}
|
||||
*/
|
||||
export class PageRefreshAction implements Action {
|
||||
export class PageRefreshAction implements RendererAction {
|
||||
async run(
|
||||
action: ListenerAction,
|
||||
renderer: ListenerContext,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {RendererEvent} from '../utils/renderer-event';
|
||||
import {
|
||||
Action,
|
||||
RendererAction,
|
||||
ListenerAction,
|
||||
ListenerContext,
|
||||
LogicAction,
|
||||
@ -10,7 +10,7 @@ import {
|
||||
|
||||
export interface IParallelAction extends ListenerAction, LogicAction {}
|
||||
|
||||
export class ParallelAction implements Action {
|
||||
export class ParallelAction implements RendererAction {
|
||||
async run(
|
||||
action: IParallelAction,
|
||||
renderer: ListenerContext,
|
||||
|
@ -2,7 +2,7 @@ import {inflate} from 'zlib';
|
||||
import {RendererEvent} from '../utils/renderer-event';
|
||||
import {evalExpression} from '../utils/tpl';
|
||||
import {
|
||||
Action,
|
||||
RendererAction,
|
||||
ListenerAction,
|
||||
ListenerContext,
|
||||
LogicAction,
|
||||
@ -15,7 +15,7 @@ export interface ISwitchAction extends ListenerAction, LogicAction {}
|
||||
/**
|
||||
* 排他动作
|
||||
*/
|
||||
export class SwitchAction implements Action {
|
||||
export class SwitchAction implements RendererAction {
|
||||
async run(
|
||||
action: ISwitchAction,
|
||||
renderer: ListenerContext,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {RendererEvent} from '../utils/renderer-event';
|
||||
import {
|
||||
Action,
|
||||
RendererAction,
|
||||
ListenerAction,
|
||||
ListenerContext,
|
||||
registerAction
|
||||
@ -26,7 +26,7 @@ export interface IToastAction extends ListenerAction {
|
||||
/**
|
||||
* 全局toast
|
||||
*/
|
||||
export class ToastAction implements Action {
|
||||
export class ToastAction implements RendererAction {
|
||||
async run(
|
||||
action: IToastAction,
|
||||
renderer: ListenerContext,
|
||||
|
26
src/env.tsx
26
src/env.tsx
@ -6,12 +6,6 @@ import {RendererConfig} from './factory';
|
||||
import {ThemeInstance} from './theme';
|
||||
import {Action, Api, Payload, Schema} from './types';
|
||||
import hoistNonReactStatic from 'hoist-non-react-statics';
|
||||
import {
|
||||
RendererEvent,
|
||||
RendererEventListener,
|
||||
EventListeners
|
||||
} from './utils/renderer-event';
|
||||
import {IScopedContext} from './Scoped';
|
||||
|
||||
export interface RendererEnv {
|
||||
fetcher: (api: Api, data?: any, options?: object) => Promise<Payload>;
|
||||
@ -69,26 +63,6 @@ export interface RendererEnv {
|
||||
) => Promise<React.ReactType> | React.ReactType | JSX.Element | void;
|
||||
loadChartExtends?: () => void | Promise<void>;
|
||||
useMobileUI?: boolean;
|
||||
bindEvent: (context: any) => (() => void) | undefined;
|
||||
dispatchEvent: (
|
||||
e:
|
||||
| string
|
||||
| React.ClipboardEvent<any>
|
||||
| React.DragEvent<any>
|
||||
| React.ChangeEvent<any>
|
||||
| React.KeyboardEvent<any>
|
||||
| React.TouchEvent<any>
|
||||
| React.WheelEvent<any>
|
||||
| React.AnimationEvent<any>
|
||||
| React.TransitionEvent<any>
|
||||
| React.MouseEvent<any>,
|
||||
context: any,
|
||||
scoped: IScopedContext,
|
||||
data: any,
|
||||
broadcast?: RendererEvent<any>
|
||||
) => Promise<RendererEvent<any> | undefined>;
|
||||
rendererEventListeners: RendererEventListener[];
|
||||
|
||||
/**
|
||||
* 过滤 html 标签,可用来添加 xss 保护逻辑
|
||||
*/
|
||||
|
109
src/factory.tsx
109
src/factory.tsx
@ -4,7 +4,6 @@ import {getEnv, destroy} from 'mobx-state-tree';
|
||||
import {wrapFetcher} from './utils/api';
|
||||
import {normalizeLink} from './utils/normalizeLink';
|
||||
import {
|
||||
createObject,
|
||||
findIndex,
|
||||
isObject,
|
||||
JSONTraverse,
|
||||
@ -13,9 +12,7 @@ import {
|
||||
string2regExp
|
||||
} from './utils/helper';
|
||||
import {
|
||||
Api,
|
||||
fetcherResult,
|
||||
Payload,
|
||||
SchemaNode,
|
||||
Schema,
|
||||
Action,
|
||||
@ -23,8 +20,8 @@ import {
|
||||
PlainObject
|
||||
} from './types';
|
||||
import {observer} from 'mobx-react';
|
||||
import Scoped, {IScopedContext} from './Scoped';
|
||||
import {getTheme, ThemeInstance, ThemeProps} from './theme';
|
||||
import Scoped from './Scoped';
|
||||
import {getTheme, ThemeProps} from './theme';
|
||||
import find from 'lodash/find';
|
||||
import Alert from './components/Alert2';
|
||||
import {toast} from './components/Toast';
|
||||
@ -34,14 +31,7 @@ import ScopedRootRenderer, {RootRenderProps} from './Root';
|
||||
import {HocStoreFactory} from './WithStore';
|
||||
import {EnvContext, RendererEnv} from './env';
|
||||
import {envOverwrite} from './envOverwrite';
|
||||
import {
|
||||
EventListeners,
|
||||
createRendererEvent,
|
||||
RendererEventListener,
|
||||
OnEventProps,
|
||||
RendererEvent
|
||||
} from './utils/renderer-event';
|
||||
import {runActions} from './actions/Action';
|
||||
import {OnEventProps} from './utils/renderer-event';
|
||||
import {enableDebug} from './utils/debug';
|
||||
|
||||
export interface TestFunc {
|
||||
@ -283,7 +273,6 @@ const defaultOptions: RenderOptions = {
|
||||
location.search.indexOf('amisDebug=1') !== -1 ??
|
||||
false,
|
||||
loadRenderer,
|
||||
rendererEventListeners: [],
|
||||
fetcher() {
|
||||
return Promise.reject('fetcher is required');
|
||||
},
|
||||
@ -384,98 +373,6 @@ const defaultOptions: RenderOptions = {
|
||||
},
|
||||
// 用于跟踪用户在界面中的各种操作
|
||||
tracker(eventTrack: EventTrack, props: PlainObject) {},
|
||||
// 返回解绑函数
|
||||
bindEvent(renderer: any) {
|
||||
if (!renderer) {
|
||||
return undefined;
|
||||
}
|
||||
const listeners: EventListeners = renderer.props.$schema.onEvent;
|
||||
if (listeners) {
|
||||
// 暂存
|
||||
for (let key of Object.keys(listeners)) {
|
||||
const listener = this.rendererEventListeners.some(
|
||||
(item: RendererEventListener) =>
|
||||
item.renderer === renderer && item.type === key
|
||||
);
|
||||
if (!listener) {
|
||||
this.rendererEventListeners.push({
|
||||
renderer,
|
||||
type: key,
|
||||
weight: listeners[key].weight || 0,
|
||||
actions: listeners[key].actions
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return () => {
|
||||
this.rendererEventListeners = this.rendererEventListeners.filter(
|
||||
(item: RendererEventListener) => item.renderer !== renderer
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
return undefined;
|
||||
},
|
||||
async dispatchEvent(
|
||||
e: string | React.MouseEvent<any>,
|
||||
renderer: React.Component<RendererProps>,
|
||||
scoped: IScopedContext,
|
||||
data: any,
|
||||
broadcast?: RendererEvent<any>
|
||||
) {
|
||||
let unbindEvent = null;
|
||||
const eventName = typeof e === 'string' ? e : e.type;
|
||||
|
||||
if (!broadcast) {
|
||||
const eventConfig = renderer?.props?.onEvent?.[eventName];
|
||||
|
||||
if (!eventConfig) {
|
||||
// 没命中也没关系
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
unbindEvent = this.bindEvent(renderer);
|
||||
}
|
||||
|
||||
// 没有可处理的监听
|
||||
if (!this.rendererEventListeners.length) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
// 如果是广播动作,就直接复用
|
||||
const rendererEvent =
|
||||
broadcast ||
|
||||
createRendererEvent(eventName, {
|
||||
env: this,
|
||||
nativeEvent: e,
|
||||
data,
|
||||
scoped
|
||||
});
|
||||
|
||||
// 过滤&排序
|
||||
const listeners = this.rendererEventListeners
|
||||
.filter(
|
||||
(item: RendererEventListener) =>
|
||||
item.type === eventName &&
|
||||
(broadcast ? true : item.renderer === renderer)
|
||||
)
|
||||
.sort(
|
||||
(prev: RendererEventListener, next: RendererEventListener) =>
|
||||
next.weight - prev.weight
|
||||
);
|
||||
|
||||
for (let listener of listeners) {
|
||||
await runActions(listener.actions, listener.renderer, rendererEvent);
|
||||
|
||||
// 停止后续监听器执行
|
||||
if (rendererEvent.stoped) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unbindEvent?.();
|
||||
|
||||
return rendererEvent;
|
||||
},
|
||||
rendererResolver: resolveRenderer,
|
||||
replaceTextIgnoreKeys: [
|
||||
'type',
|
||||
|
@ -1,4 +1,6 @@
|
||||
import {ListenerAction, ListenerContext} from '../actions/Action';
|
||||
import {ListenerAction, ListenerContext, runActions} from '../actions/Action';
|
||||
import {RendererProps} from '../factory';
|
||||
import {IScopedContext} from '../Scoped';
|
||||
|
||||
// 事件监听器
|
||||
export interface EventListeners {
|
||||
@ -20,7 +22,7 @@ export interface OnEventProps {
|
||||
|
||||
// 渲染器事件监听器
|
||||
export interface RendererEventListener {
|
||||
renderer: ListenerContext;
|
||||
renderer: React.Component<RendererProps>;
|
||||
type: string;
|
||||
weight: number;
|
||||
actions: ListenerAction[];
|
||||
@ -43,6 +45,8 @@ export interface RendererEventContext {
|
||||
[propName: string]: any;
|
||||
}
|
||||
|
||||
let rendererEventListeners: RendererEventListener[] = [];
|
||||
|
||||
// 创建渲染器事件对象
|
||||
export function createRendererEvent<T extends RendererEventContext>(
|
||||
type: string,
|
||||
@ -72,4 +76,103 @@ export function createRendererEvent<T extends RendererEventContext>(
|
||||
return rendererEvent;
|
||||
}
|
||||
|
||||
// 绑定事件
|
||||
export const bindEvent = (renderer: any) => {
|
||||
if (!renderer) {
|
||||
return undefined;
|
||||
}
|
||||
const listeners: EventListeners = renderer.props.$schema.onEvent;
|
||||
if (listeners) {
|
||||
// 暂存
|
||||
for (let key of Object.keys(listeners)) {
|
||||
const listener = rendererEventListeners.some(
|
||||
(item: RendererEventListener) =>
|
||||
item.renderer === renderer && item.type === key
|
||||
);
|
||||
if (!listener) {
|
||||
rendererEventListeners.push({
|
||||
renderer,
|
||||
type: key,
|
||||
weight: listeners[key].weight || 0,
|
||||
actions: listeners[key].actions
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return () => {
|
||||
rendererEventListeners = rendererEventListeners.filter(
|
||||
(item: RendererEventListener) => item.renderer !== renderer
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
||||
// 触发事件
|
||||
export async function dispatchEvent(
|
||||
e: string | React.MouseEvent<any>,
|
||||
renderer: React.Component<RendererProps>,
|
||||
scoped: IScopedContext,
|
||||
data: any,
|
||||
broadcast?: RendererEvent<any>
|
||||
): Promise<RendererEvent<any> | void> {
|
||||
let unbindEvent = null;
|
||||
const eventName = typeof e === 'string' ? e : e.type;
|
||||
|
||||
if (!broadcast) {
|
||||
const eventConfig = renderer?.props?.onEvent?.[eventName];
|
||||
|
||||
if (!eventConfig) {
|
||||
// 没命中也没关系
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
unbindEvent = bindEvent(renderer);
|
||||
}
|
||||
|
||||
// 没有可处理的监听
|
||||
if (!rendererEventListeners.length) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
// 如果是广播动作,就直接复用
|
||||
const rendererEvent =
|
||||
broadcast ||
|
||||
createRendererEvent(eventName, {
|
||||
env: renderer?.props?.env,
|
||||
nativeEvent: e,
|
||||
data,
|
||||
scoped
|
||||
});
|
||||
|
||||
// 过滤&排序
|
||||
const listeners = rendererEventListeners
|
||||
.filter(
|
||||
(item: RendererEventListener) =>
|
||||
item.type === eventName &&
|
||||
(broadcast ? true : item.renderer === renderer)
|
||||
)
|
||||
.sort(
|
||||
(prev: RendererEventListener, next: RendererEventListener) =>
|
||||
next.weight - prev.weight
|
||||
);
|
||||
|
||||
for (let listener of listeners) {
|
||||
await runActions(listener.actions, listener.renderer, rendererEvent);
|
||||
|
||||
// 停止后续监听器执行
|
||||
if (rendererEvent.stoped) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unbindEvent?.();
|
||||
|
||||
return Promise.resolve(rendererEvent);
|
||||
}
|
||||
|
||||
export const getRendererEventListeners = () => {
|
||||
return rendererEventListeners;
|
||||
};
|
||||
|
||||
export default {};
|
||||
|
Loading…
Reference in New Issue
Block a user