diff --git a/packages/amis-core/src/SchemaRenderer.tsx b/packages/amis-core/src/SchemaRenderer.tsx index c0ddb0c51..a452caf63 100644 --- a/packages/amis-core/src/SchemaRenderer.tsx +++ b/packages/amis-core/src/SchemaRenderer.tsx @@ -26,7 +26,12 @@ import { formateId } from './utils/helper'; import {SimpleMap} from './utils/SimpleMap'; -import {bindEvent, dispatchEvent, RendererEvent} from './utils/renderer-event'; +import { + bindEvent, + bindGlobalEvent, + dispatchEvent, + RendererEvent +} from './utils/renderer-event'; import {isAlive} from 'mobx-state-tree'; import {reaction} from 'mobx'; import {resolveVariableAndFilter} from './utils/tpl-builtin'; @@ -110,6 +115,7 @@ export class SchemaRenderer extends React.Component { toDispose: Array<() => any> = []; unbindEvent: (() => void) | undefined = undefined; + unbindGlobalEvent: (() => void) | undefined = undefined; isStatic: any = undefined; constructor(props: SchemaRendererProps) { @@ -175,6 +181,7 @@ export class SchemaRenderer extends React.Component { this.toDispose.forEach(fn => fn()); this.toDispose = []; this.unbindEvent?.(); + this.unbindGlobalEvent?.(); this.removeAnimationStyle(); } @@ -299,7 +306,10 @@ export class SchemaRenderer extends React.Component { if (ref) { // 这里无法区分监听的是不是广播,所以又bind一下,主要是为了绑广播 this.unbindEvent?.(); + this.unbindGlobalEvent?.(); + this.unbindEvent = bindEvent(ref); + this.unbindGlobalEvent = bindGlobalEvent(ref); } this.cRef = ref; } diff --git a/packages/amis-core/src/actions/GlobalEventAction.ts b/packages/amis-core/src/actions/GlobalEventAction.ts new file mode 100644 index 000000000..b496a1e8d --- /dev/null +++ b/packages/amis-core/src/actions/GlobalEventAction.ts @@ -0,0 +1,46 @@ +/** + * @file GlobalEventAction.ts + * + * @created: 2024/11/05 + */ + +import {createObject} from '../utils/helper'; +import {RendererEvent, dispatchGlobalEvent} from '../utils/renderer-event'; +import { + registerAction, + RendererAction, + ListenerAction, + ListenerContext +} from './Action'; + +export interface IGlobalEventAction extends ListenerAction { + actionType: string; +} + +/** + * GlobalEventAction + * + * @export + * @class GlobalEventAction + * @implements {RendererAction} + */ +export class GlobalEventAction implements RendererAction { + async run( + action: IGlobalEventAction, + renderer: ListenerContext, + event: RendererEvent + ) { + if (!action.eventName) { + console.error('eventName 未定义,请定义事件名称'); + return; + } + + event.setData(createObject(event.data, action.data ?? {})); + + console.log(action.eventName); + // 直接触发对应的动作 + return await dispatchGlobalEvent(action.eventName, action.data); + } +} + +registerAction('globalEvent', new GlobalEventAction()); diff --git a/packages/amis-core/src/actions/index.ts b/packages/amis-core/src/actions/index.ts index 49d8e6312..056378355 100644 --- a/packages/amis-core/src/actions/index.ts +++ b/packages/amis-core/src/actions/index.ts @@ -22,5 +22,6 @@ import './ToastAction'; import './WaitAction'; import './PageAction'; import './PrintAction'; +import './GlobalEventAction'; export * from './Action'; diff --git a/packages/amis-core/src/utils/renderer-event.ts b/packages/amis-core/src/utils/renderer-event.ts index f98615fa8..8fcd6f688 100644 --- a/packages/amis-core/src/utils/renderer-event.ts +++ b/packages/amis-core/src/utils/renderer-event.ts @@ -195,6 +195,42 @@ export const bindEvent = (renderer: any) => { return undefined; }; +export const bindGlobalEvent = (renderer: any) => { + if (!renderer) { + return undefined; + } + const listeners: EventListeners = renderer.props.$schema.onEvent; + let bcs = []; + if (listeners) { + // 暂存 + for (let key of Object.keys(listeners)) { + const listener = listeners[key]; + const bc = new BroadcastChannel(key); + bcs.push({ + renderer: renderer, + bc + }); + bc.onmessage = e => { + const {eventName, data} = e.data; + const rendererEvent = createRendererEvent(eventName, { + env: renderer?.props?.env, + nativeEvent: eventName, + scoped: renderer?.context, + data + }); + + runActions(listener.actions, renderer, rendererEvent); + }; + } + return () => { + bcs + .filter(item => item.renderer === renderer) + .forEach(item => item.bc.close()); + }; + } + return void 0; +}; + // 触发事件 export async function dispatchEvent( e: string | React.MouseEvent, @@ -313,6 +349,14 @@ export async function dispatchEvent( return Promise.resolve(rendererEvent); } +export async function dispatchGlobalEvent(eventName: string, data: any) { + const bc = new BroadcastChannel(eventName); + bc.postMessage({ + eventName, + data + }); +} + export const getRendererEventListeners = () => { return rendererEventListeners; };