diff --git a/packages/amis-core/src/SchemaRenderer.tsx b/packages/amis-core/src/SchemaRenderer.tsx index a452caf63..e4672df66 100644 --- a/packages/amis-core/src/SchemaRenderer.tsx +++ b/packages/amis-core/src/SchemaRenderer.tsx @@ -28,7 +28,7 @@ import { import {SimpleMap} from './utils/SimpleMap'; import { bindEvent, - bindGlobalEvent, + bindGlobalEventForRenderer as bindGlobalEvent, dispatchEvent, RendererEvent } from './utils/renderer-event'; diff --git a/packages/amis-core/src/index.tsx b/packages/amis-core/src/index.tsx index e7e67aaa0..99315d0c0 100644 --- a/packages/amis-core/src/index.tsx +++ b/packages/amis-core/src/index.tsx @@ -129,6 +129,8 @@ import {StatusScoped} from './StatusScoped'; import styleManager from './StyleManager'; +import {bindGlobalEvent, dispatchGlobalEvent} from './utils/renderer-event'; + // @ts-ignore export const version = '__buildVersion'; (window as any).amisVersionInfo = { @@ -181,6 +183,9 @@ export { getClassPrefix, classnames, makeClassnames, + // 全局广播事件 + bindGlobalEvent, + dispatchGlobalEvent, // 多语言相关 getDefaultLocale, setDefaultLocale, diff --git a/packages/amis-core/src/utils/renderer-event.ts b/packages/amis-core/src/utils/renderer-event.ts index 5128e5368..f0618167a 100644 --- a/packages/amis-core/src/utils/renderer-event.ts +++ b/packages/amis-core/src/utils/renderer-event.ts @@ -7,6 +7,7 @@ import {createObject, extendObject} from './object'; import debounce from 'lodash/debounce'; import {resolveVariableAndFilterForAsync} from './resolveVariableAndFilterForAsync'; import {evalExpression, evalExpressionWithConditionBuilderAsync} from './tpl'; +import type {PlainObject} from '../types'; export interface debounceConfig { maxWait?: number; @@ -195,7 +196,7 @@ export const bindEvent = (renderer: any) => { return undefined; }; -export const bindGlobalEvent = (renderer: any) => { +export const bindGlobalEventForRenderer = (renderer: any) => { if (!renderer) { return undefined; } @@ -237,6 +238,26 @@ export const bindGlobalEvent = (renderer: any) => { return void 0; }; +export const bindGlobalEvent = ( + eventName: string, + callback: (data: PlainObject) => void +) => { + if (!BroadcastChannel) { + console.error('BroadcastChannel is not supported in your browser'); + return; + } + + const bc = new BroadcastChannel(eventName); + bc.onmessage = e => { + const {eventName: name, data} = e.data; + if (name === eventName) { + callback(data); + } + }; + + return () => bc.close(); +}; + // 触发事件 export async function dispatchEvent( e: string | React.MouseEvent, diff --git a/packages/amis-editor-core/scss/control/_event-action.scss b/packages/amis-editor-core/scss/control/_event-action.scss index 521a0a960..97dd550ee 100644 --- a/packages/amis-editor-core/scss/control/_event-action.scss +++ b/packages/amis-editor-core/scss/control/_event-action.scss @@ -26,6 +26,25 @@ display: none; } } + .add-event-dropdown-global-event { + position: relative; + &::after { + position: absolute; + content: '全局事件'; + display: flex; + align-items: center; + padding: 0 6px; + right: 4px; + top: 4px; + bottom: 4px; + font-size: 12px; + color: #fff; + background-color: #2468f2; + border-radius: 4px; + transform: scale(0.8); + transform-origin: center; + } + } } ul { width: 100%; @@ -71,6 +90,32 @@ } } } + + .event-label { + display: flex; + align-items: center; + .event-label-key { + flex: 1; + max-width: 100px; + overflow: hidden; + text-overflow: ellipsis; + } + .global-event-tip { + width: 48px; + display: flex; + > span { + transform: scale(0.7); + transform-origin: left; + background-color: #2468f2; + border-radius: 4px; + font-size: 12px; + color: #fff; + padding: 4px 6px; + flex-shrink: 0; + text-align: center; + } + } + } } &-desc { margin: #{px2rem(12px)}; @@ -206,9 +251,6 @@ clip-path: inset(-5px 0px 0px 0px); } } - &-content-withglobalevent { - margin-top: 100px !important; - } .no-bd-btm { border-bottom: none; } diff --git a/packages/amis-editor/src/renderer/event-control/index.tsx b/packages/amis-editor/src/renderer/event-control/index.tsx index 3022d4e45..72f51c4a9 100644 --- a/packages/amis-editor/src/renderer/event-control/index.tsx +++ b/packages/amis-editor/src/renderer/event-control/index.tsx @@ -1092,7 +1092,7 @@ export class EventControl extends React.Component< getComponents, allComponents, render, - globalEvents, + globalEvents = [], subscribeSchemaSubmit } = this.props; const { @@ -1167,65 +1167,51 @@ export class EventControl extends React.Component< disabled: false, className: 'block w-full add-event-dropdown', closeOnClick: true, - buttons: events.map(item => ({ - type: 'button', - disabledTip: '您已添加该事件', - tooltipPlacement: 'left', - disabled: Object.keys(onEvent).includes(item.eventName), - actionType: '', - label: item.eventLabel, - onClick: this.addEvent.bind( - this, - item, - Object.keys(onEvent).includes(item.eventName) - ) - })) + buttons: [ + ...events.map(item => ({ + type: 'button', + disabledTip: '您已添加该事件', + tooltipPlacement: 'left', + disabled: Object.keys(onEvent).includes(item.eventName), + actionType: '', + label: item.eventLabel, + onClick: this.addEvent.bind( + this, + item, + Object.keys(onEvent).includes(item.eventName) + ) + })), + ...globalEvents.map(item => ({ + type: 'button', + disabledTip: '您已添加该全局事件', + tooltipPlacement: 'left', + disabled: Object.keys(onEvent).includes(item.name), + actionType: '', + className: 'add-event-dropdown-global-event', + label: item.label, + onClick: this.addGlobalEvent.bind( + this, + item, + Object.keys(onEvent).includes(item.name) + ) + })) + ] }, { popOverContainer: null // amis 渲染挂载节点会使用 this.target } )} - - {globalEvents - ? render( - 'dropdown', - { - type: 'dropdown-button', - level: 'enhance', - label: '添加全局事件', - disabled: false, - className: 'block w-full add-event-dropdown mt-2', - closeOnClick: true, - buttons: globalEvents.map(item => ({ - type: 'button', - disabledTip: '您已添加该事件', - tooltipPlacement: 'left', - disabled: Object.keys(onEvent).includes(item.name), - actionType: '', - label: item.label, - onClick: this.addGlobalEvent.bind( - this, - item, - Object.keys(onEvent).includes(item.name) - ) - })) - }, - { - popOverContainer: null // amis 渲染挂载节点会使用 this.target - } - ) - : null}