feat(editor): stage overlay 支持放大缩小

This commit is contained in:
roymondchen 2025-06-20 19:47:51 +08:00
parent 95d6263f42
commit 32681964b3
5 changed files with 34 additions and 18 deletions

View File

@ -45,6 +45,7 @@ export const useStage = (stageOptions: StageOptions) => {
updateDragEl: stageOptions.updateDragEl, updateDragEl: stageOptions.updateDragEl,
guidesOptions: stageOptions.guidesOptions, guidesOptions: stageOptions.guidesOptions,
disabledMultiSelect: stageOptions.disabledMultiSelect, disabledMultiSelect: stageOptions.disabledMultiSelect,
disabledRule: stageOptions.disabledRule,
}); });
watch( watch(

View File

@ -1,9 +1,19 @@
<template> <template>
<div v-if="stageOverlayVisible" class="m-editor-stage-overlay" @click="closeOverlayHandler"> <div v-if="stageOverlayVisible" class="m-editor-stage-overlay">
<TMagicIcon class="m-editor-stage-overlay-close" :size="'20'" @click="closeOverlayHandler" <TMagicIcon class="m-editor-stage-overlay-close" :size="'30'" @click="closeOverlayHandler"
><CloseBold ><CloseBold
/></TMagicIcon> /></TMagicIcon>
<div ref="stageOverlay" class="m-editor-stage-overlay-container" :style="style" @click.stop></div>
<ScrollViewer
class="m-editor-stage"
:width="wrapWidth"
:height="wrapHeight"
:wrap-width="columnWidth.center"
:wrap-height="frameworkRect.height"
:zoom="zoom"
>
<div ref="stageOverlay" class="m-editor-stage-container" :style="style"></div>
</ScrollViewer>
</div> </div>
</template> </template>
@ -13,10 +23,11 @@ import { CloseBold } from '@element-plus/icons-vue';
import { TMagicIcon } from '@tmagic/design'; import { TMagicIcon } from '@tmagic/design';
import ScrollViewer from '@editor/components/ScrollViewer.vue';
import { useServices } from '@editor/hooks/use-services'; import { useServices } from '@editor/hooks/use-services';
import type { StageOptions } from '@editor/type'; import type { StageOptions } from '@editor/type';
const { stageOverlayService, editorService } = useServices(); const { stageOverlayService, editorService, uiService } = useServices();
const stageOptions = inject<StageOptions>('stageOptions'); const stageOptions = inject<StageOptions>('stageOptions');
@ -26,10 +37,12 @@ const stageOverlayVisible = computed(() => stageOverlayService.get('stageOverlay
const wrapWidth = computed(() => stageOverlayService.get('wrapWidth')); const wrapWidth = computed(() => stageOverlayService.get('wrapWidth'));
const wrapHeight = computed(() => stageOverlayService.get('wrapHeight')); const wrapHeight = computed(() => stageOverlayService.get('wrapHeight'));
const stage = computed(() => editorService.get('stage')); const stage = computed(() => editorService.get('stage'));
const zoom = computed(() => uiService.get('zoom'));
const columnWidth = computed(() => uiService.get('columnWidth'));
const frameworkRect = computed(() => uiService.get('frameworkRect'));
const style = computed(() => ({ const style = computed(() => ({
width: `${wrapWidth.value}px`, transform: `scale(${zoom.value})`,
height: `${wrapHeight.value}px`,
})); }));
watch(stage, (stage) => { watch(stage, (stage) => {
@ -43,6 +56,12 @@ watch(stage, (stage) => {
} }
}); });
watch(zoom, (zoom) => {
const stage = stageOverlayService.get('stage');
if (!stage || !zoom) return;
stage.setZoom(zoom);
});
watch(stageOverlayEl, (stageOverlay) => { watch(stageOverlayEl, (stageOverlay) => {
const subStage = stageOverlayService.createStage(stageOptions); const subStage = stageOverlayService.createStage(stageOptions);
stageOverlayService.set('stage', subStage); stageOverlayService.set('stage', subStage);

View File

@ -97,9 +97,9 @@ class StageOverlay extends BaseService {
public createStage(stageOptions: StageOptions = {}) { public createStage(stageOptions: StageOptions = {}) {
return useStage({ return useStage({
...stageOptions, ...stageOptions,
zoom: 1,
runtimeUrl: '', runtimeUrl: '',
autoScrollIntoView: false, autoScrollIntoView: false,
disabledRule: true,
render: async (stage: StageCore) => { render: async (stage: StageCore) => {
this.copyDocumentElement(); this.copyDocumentElement();

View File

@ -35,22 +35,15 @@
width: 100%; width: 100%;
height: 100%; height: 100%;
background-color: #fff; background-color: #fff;
display: flex;
z-index: 20; z-index: 20;
overflow: auto;
}
.m-editor-stage-overlay-container {
position: relative;
flex-shrink: 0;
margin: auto;
box-shadow: rgba(0, 0, 0, 0.04) 0px 3px 5px;
} }
.m-editor-stage-overlay-close.tmagic-design-icon { .m-editor-stage-overlay-close.tmagic-design-icon {
position: fixed; position: fixed;
right: 20px; right: 20px;
top: 10px; top: 10px;
cursor: pointer;
z-index: 1;
} }
.m-editor-stage-float-button { .m-editor-stage-float-button {
@ -66,8 +59,10 @@
background-color: #ffffff; background-color: #ffffff;
transition: background-color 0.2s; transition: background-color 0.2s;
color: rgba(0, 0, 0, 0.88); color: rgba(0, 0, 0, 0.88);
box-shadow: 0 6px 16px 0 rgba(0, 0, 0, 0.08), box-shadow:
0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 9px 28px 8px rgba(0, 0, 0, 0.05); 0 6px 16px 0 rgba(0, 0, 0, 0.08),
0 3px 6px -4px rgba(0, 0, 0, 0.12),
0 9px 28px 8px rgba(0, 0, 0, 0.05);
} }
.m-editor-node-list-menu { .m-editor-node-list-menu {

View File

@ -164,6 +164,7 @@ export interface StageOptions {
renderType?: RenderType; renderType?: RenderType;
guidesOptions?: Partial<GuidesOptions>; guidesOptions?: Partial<GuidesOptions>;
disabledMultiSelect?: boolean; disabledMultiSelect?: boolean;
disabledRule?: boolean;
zoom?: number; zoom?: number;
} }