diff --git a/packages/editor/src/hooks/use-stage.ts b/packages/editor/src/hooks/use-stage.ts index ebd93637..cd0012ea 100644 --- a/packages/editor/src/hooks/use-stage.ts +++ b/packages/editor/src/hooks/use-stage.ts @@ -1,4 +1,5 @@ import { computed, watch } from 'vue'; +import { cloneDeep } from 'lodash-es'; import type { MNode } from '@tmagic/core'; import StageCore, { GuidesType, RemoveEventData, SortEventData, UpdateEventData } from '@tmagic/stage'; @@ -131,5 +132,17 @@ export const useStage = (stageOptions: StageOptions) => { } }); + stage.on('rerender', () => { + const node = editorService.get('node'); + + if (!node || !root.value) return; + + stage.update({ + config: cloneDeep(node), + parentId: editorService.getParentById(node.id)?.id, + root: cloneDeep(root.value), + }); + }); + return stage; }; diff --git a/packages/editor/src/layouts/workspace/Workspace.vue b/packages/editor/src/layouts/workspace/Workspace.vue index 6bd84aaf..3d75d5a5 100644 --- a/packages/editor/src/layouts/workspace/Workspace.vue +++ b/packages/editor/src/layouts/workspace/Workspace.vue @@ -4,7 +4,8 @@ import { computed, inject } from 'vue'; -import type { MenuButton, MenuComponent, Services, WorkspaceSlots } from '@editor/type'; +import type { MenuButton, MenuComponent, Services, StageOptions, WorkspaceSlots } from '@editor/type'; import MagicStage from './viewer/Stage.vue'; import Breadcrumb from './Breadcrumb.vue'; @@ -40,6 +41,8 @@ withDefaults( }, ); +const stageOptions = inject('stageOptions'); + const services = inject('services'); const page = computed(() => services?.editorService.get('page')); diff --git a/packages/editor/src/layouts/workspace/viewer/Stage.vue b/packages/editor/src/layouts/workspace/viewer/Stage.vue index c32938af..29d9455a 100644 --- a/packages/editor/src/layouts/workspace/viewer/Stage.vue +++ b/packages/editor/src/layouts/workspace/viewer/Stage.vue @@ -64,8 +64,9 @@ defineOptions({ name: 'MEditorStage', }); -withDefaults( +const props = withDefaults( defineProps<{ + stageOptions: StageOptions; stageContentMenu: (MenuButton | MenuComponent)[]; disabledStageOverlay?: boolean; customContentMenu?: (menus: (MenuButton | MenuComponent)[], type: string) => (MenuButton | MenuComponent)[]; @@ -79,7 +80,6 @@ let stage: StageCore | null = null; let runtime: Runtime | null = null; const services = inject('services'); -const stageOptions = inject('stageOptions'); const stageLoading = computed(() => services?.editorService.get('stageLoading') || false); @@ -100,9 +100,9 @@ watchEffect(() => { if (stage || !page.value) return; if (!stageContainer.value) return; - if (!(stageOptions?.runtimeUrl || stageOptions?.render) || !root.value) return; + if (!(props.stageOptions?.runtimeUrl || props.stageOptions?.render) || !root.value) return; - stage = useStage(stageOptions); + stage = useStage(props.stageOptions); stage.on('select', () => { stageWrap.value?.container?.focus(); @@ -129,6 +129,7 @@ watchEffect(() => { onBeforeUnmount(() => { stage?.destroy(); + services?.editorService.set('stage', null); }); watch(zoom, (zoom) => { @@ -216,7 +217,9 @@ const dropHandler = async (e: DragEvent) => { e.preventDefault(); const doc = stage?.renderer?.contentWindow?.document; - const parentEl: HTMLElement | null | undefined = doc?.querySelector(`.${stageOptions?.containerHighlightClassName}`); + const parentEl: HTMLElement | null | undefined = doc?.querySelector( + `.${props.stageOptions?.containerHighlightClassName}`, + ); let parent: MContainer | undefined | null = page.value; const parentId = getIdFromEl()(parentEl); diff --git a/packages/stage/src/ActionManager.ts b/packages/stage/src/ActionManager.ts index fe0859d4..08026d7f 100644 --- a/packages/stage/src/ActionManager.ts +++ b/packages/stage/src/ActionManager.ts @@ -445,6 +445,9 @@ export default class ActionManager extends EventEmitter { }; this.emit('remove', data); }) + .on(AbleActionEventType.RERENDER, () => { + this.emit('rerender'); + }) .on('drag-start', (e: OnDragStart) => { this.emit('drag-start', e); }); diff --git a/packages/stage/src/MoveableActionsAble.ts b/packages/stage/src/MoveableActionsAble.ts index a409e82f..de76b665 100644 --- a/packages/stage/src/MoveableActionsAble.ts +++ b/packages/stage/src/MoveableActionsAble.ts @@ -57,6 +57,21 @@ export default ( return React.createElement('button', options.props || {}, ...(options.children || [])); }), + React.createElement( + 'button', + { + className: 'moveable-button moveable-rerender-button', + title: '重新渲染', + onClick: () => { + handler(AbleActionEventType.RERENDER); + }, + }, + React.createElement('img', { + src: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGNsYXNzPSJpY29uIGljb24tdGFibGVyIGljb24tdGFibGVyLXJlcGxhY2UiIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZT0iI2ZmZmZmZiIgZmlsbD0ibm9uZSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj4KICA8cGF0aCBzdHJva2U9Im5vbmUiIGQ9Ik0wIDBoMjR2MjRIMHoiIGZpbGw9Im5vbmUiLz4KICA8cmVjdCB4PSIzIiB5PSIzIiB3aWR0aD0iNiIgaGVpZ2h0PSI2IiByeD0iMSIgLz4KICA8cmVjdCB4PSIxNSIgeT0iMTUiIHdpZHRoPSI2IiBoZWlnaHQ9IjYiIHJ4PSIxIiAvPgogIDxwYXRoIGQ9Ik0yMSAxMXYtM2EyIDIgMCAwIDAgLTIgLTJoLTZsMyAzbTAgLTZsLTMgMyIgLz4KICA8cGF0aCBkPSJNMyAxM3YzYTIgMiAwIDAgMCAyIDJoNmwtMyAtM20wIDZsMyAtMyIgLz4KPC9zdmc+CgoK', + width: '16', + height: '16', + }), + ), React.createElement( 'button', { diff --git a/packages/stage/src/StageCore.ts b/packages/stage/src/StageCore.ts index 3511186b..be0a0363 100644 --- a/packages/stage/src/StageCore.ts +++ b/packages/stage/src/StageCore.ts @@ -373,6 +373,9 @@ export default class StageCore extends EventEmitter { .on('select-parent', () => { this.emit('select-parent'); }) + .on('rerender', () => { + this.emit('rerender'); + }) .on('remove', (data: RemoveEventData) => { this.emit('remove', data); }); diff --git a/packages/stage/src/const.ts b/packages/stage/src/const.ts index 7f254644..2833d8bf 100644 --- a/packages/stage/src/const.ts +++ b/packages/stage/src/const.ts @@ -77,6 +77,7 @@ export const SELECTED_CLASS = 'tmagic-stage-selected-area'; export enum AbleActionEventType { SELECT_PARENT = 'select-parent', REMOVE = 'remove', + RERENDER = 'rerender', } /** 将组件添加到容器的方式 */ diff --git a/packages/stage/src/moveable-able.css b/packages/stage/src/moveable-able.css index 941e1e54..4aa07991 100644 --- a/packages/stage/src/moveable-able.css +++ b/packages/stage/src/moveable-able.css @@ -106,3 +106,8 @@ top: 50%;; } +.moveable-rerender-button img { + position: absolute; + left: 2px; + top: 2px; +} diff --git a/packages/stage/src/types.ts b/packages/stage/src/types.ts index 77a5ad42..64b7f57e 100644 --- a/packages/stage/src/types.ts +++ b/packages/stage/src/types.ts @@ -251,6 +251,7 @@ export interface CoreEvents { update: [data: UpdateEventData]; sort: [data: SortEventData]; 'select-parent': []; + rerender: []; remove: [data: RemoveEventData]; highlight: [highlightEl: HTMLElement]; mousemove: [event: MouseEvent]; @@ -283,6 +284,7 @@ export interface ActionManagerEvents { sort: [data: SortEventData]; remove: [data: RemoveEventData]; select: [selectedEl: HTMLElement | null, event: MouseEvent]; + rerender: []; 'select-parent': []; 'drag-start': [event: OnDragStart]; 'multi-update': [data: UpdateEventData]; @@ -297,6 +299,7 @@ export interface DrEvents { 'update-moveable': []; [AbleActionEventType.REMOVE]: []; [AbleActionEventType.SELECT_PARENT]: []; + [AbleActionEventType.RERENDER]: []; 'drag-start': [event: OnDragStart]; update: [data: UpdateEventData]; sort: [data: SortEventData];