feat: 支持配置updateDragEl方法来调制选中框

This commit is contained in:
roymondchen 2022-06-15 14:20:59 +08:00 committed by jia000
parent 10577aea68
commit 154860c66c
8 changed files with 62 additions and 71 deletions

View File

@ -12,13 +12,7 @@
<template #workspace :editorService="editorService">
<slot name="workspace">
<workspace
:runtime-url="runtimeUrl"
:auto-scroll-into-view="autoScrollIntoView"
:render="render"
:moveable-options="moveableOptions"
:can-select="canSelect"
>
<workspace>
<template #workspace-content><slot name="workspace-content" :editorService="editorService"></slot></template>
<template #page-bar-title="{ page }"><slot name="page-bar-title" :page="page"></slot></template>
<template #page-bar-popover="{ page }"><slot name="page-bar-popover" :page="page"></slot></template>
@ -37,7 +31,7 @@
</template>
<script lang="ts">
import { defineComponent, onUnmounted, PropType, provide, toRaw, watch } from 'vue';
import { defineComponent, onUnmounted, PropType, provide, reactive, toRaw, watch } from 'vue';
import { EventOption } from '@tmagic/core';
import type { FormConfig } from '@tmagic/form';
@ -136,6 +130,9 @@ export default defineComponent({
/** 画布中组件选中框的移动范围 */
moveableOptions: {
type: [Object, Function] as PropType<MoveableOptions | ((core?: StageCore) => MoveableOptions)>,
default: () => (core?: StageCore) => ({
container: core?.renderer?.contentWindow?.document.getElementById('app'),
}),
},
/** 编辑器初始化时默认选中的组件ID */
@ -145,6 +142,7 @@ export default defineComponent({
canSelect: {
type: Function as PropType<(el: HTMLElement) => boolean | Promise<boolean>>,
default: (el: HTMLElement) => Boolean(el.id),
},
stageRect: {
@ -155,6 +153,10 @@ export default defineComponent({
type: Object,
default: () => ({}),
},
updateDragEl: {
type: Function as PropType<(el: HTMLDivElement, target: HTMLElement) => void>,
},
},
emits: ['props-panel-mounted', 'update:modelValue'],
@ -249,6 +251,17 @@ export default defineComponent({
provide('layerContentMenu', props.layerContentMenu);
provide('stageContentMenu', props.stageContentMenu);
provide(
'stageOptions',
reactive({
runtimeUrl: props.runtimeUrl,
autoScrollIntoView: props.autoScrollIntoView,
render: props.render,
moveableOptions: props.moveableOptions,
canSelect: props.canSelect,
updateDragEl: props.updateDragEl,
}),
);
return services;
},

View File

@ -28,7 +28,6 @@ import {
markRaw,
onMounted,
onUnmounted,
PropType,
ref,
toRaw,
watch,
@ -37,11 +36,11 @@ import {
import { cloneDeep } from 'lodash-es';
import type { MApp, MNode, MPage } from '@tmagic/schema';
import type { MoveableOptions, Runtime, SortEventData, UpdateEventData } from '@tmagic/stage';
import type { Runtime, SortEventData, UpdateEventData } from '@tmagic/stage';
import StageCore from '@tmagic/stage';
import ScrollViewer from '@editor/components/ScrollViewer.vue';
import { Layout, Services, StageRect } from '@editor/type';
import { Layout, Services, StageOptions, StageRect } from '@editor/type';
import ViewerMenu from './ViewerMenu.vue';
@ -53,29 +52,9 @@ export default defineComponent({
ScrollViewer,
},
props: {
render: {
type: Function as PropType<() => HTMLDivElement>,
},
runtimeUrl: String,
autoScrollIntoView: Boolean,
canSelect: {
type: Function as PropType<(el: HTMLElement) => boolean | Promise<boolean>>,
default: (el: HTMLElement) => Boolean(el.id),
},
moveableOptions: {
type: [Object, Function] as PropType<MoveableOptions | ((core?: StageCore) => MoveableOptions)>,
default: () => (core?: StageCore) => ({
container: core?.renderer?.contentWindow?.document.getElementById('app'),
}),
},
},
setup(props) {
setup() {
const services = inject<Services>('services');
const stageOptions = inject<StageOptions>('stageOptions');
const stageWrap = ref<InstanceType<typeof ScrollViewer>>();
const stageContainer = ref<HTMLDivElement>();
@ -95,15 +74,15 @@ export default defineComponent({
if (stage) return;
if (!stageContainer.value) return;
if (!(props.runtimeUrl || props.render) || !root.value) return;
if (!(stageOptions?.runtimeUrl || stageOptions?.render) || !root.value) return;
stage = new StageCore({
render: props.render,
runtimeUrl: props.runtimeUrl,
render: stageOptions.render,
runtimeUrl: stageOptions.runtimeUrl,
zoom: zoom.value,
autoScrollIntoView: props.autoScrollIntoView,
autoScrollIntoView: stageOptions.autoScrollIntoView,
canSelect: (el, event, stop) => {
const elCanSelect = props.canSelect(el);
const elCanSelect = stageOptions.canSelect(el);
// ui-select
if (uiSelectMode.value && elCanSelect && event.type === 'mousedown') {
document.dispatchEvent(new CustomEvent('ui-select', { detail: el }));
@ -112,7 +91,8 @@ export default defineComponent({
return elCanSelect;
},
moveableOptions: props.moveableOptions,
moveableOptions: stageOptions.moveableOptions,
updateDragEl: stageOptions.updateDragEl,
});
services?.editorService.set('stage', markRaw(stage));

View File

@ -1,13 +1,6 @@
<template>
<div class="m-editor-workspace" tabindex="1" ref="workspace">
<magic-stage
:key="page?.id"
:runtime-url="runtimeUrl"
:auto-scroll-into-view="autoScrollIntoView"
:render="render"
:moveable-options="moveableOptions"
:can-select="canSelect"
></magic-stage>
<magic-stage :key="page?.id"></magic-stage>
<slot name="workspace-content"></slot>
@ -19,12 +12,10 @@
</template>
<script lang="ts">
import { computed, defineComponent, inject, onMounted, onUnmounted, PropType, ref } from 'vue';
import { computed, defineComponent, inject, onMounted, onUnmounted, ref } from 'vue';
import KeyController from 'keycon';
import type { MNode, MPage } from '@tmagic/schema';
import type { MoveableOptions } from '@tmagic/stage';
import StageCore from '@tmagic/stage';
import { isPage } from '@tmagic/utils';
import type { Services } from '@editor/type';
@ -40,23 +31,6 @@ export default defineComponent({
MagicStage,
},
props: {
runtimeUrl: String,
autoScrollIntoView: Boolean,
render: {
type: Function as PropType<() => HTMLDivElement>,
},
moveableOptions: {
type: [Object, Function] as PropType<MoveableOptions | ((core?: StageCore) => MoveableOptions)>,
},
canSelect: {
type: Function as PropType<(el: HTMLElement) => boolean | Promise<boolean>>,
},
},
setup() {
const services = inject<Services>('services');
const workspace = ref<HTMLDivElement>();

View File

@ -21,6 +21,7 @@ import type { Component } from 'vue';
import type { FormConfig } from '@tmagic/form';
import type { Id, MApp, MContainer, MNode, MPage } from '@tmagic/schema';
import type StageCore from '@tmagic/stage';
import type { MoveableOptions } from '@tmagic/stage';
import type { ComponentListService } from '@editor/services/componentList';
import type { EditorService } from '@editor/services/editor';
@ -45,6 +46,15 @@ export interface Services {
uiService: UiService;
}
export interface StageOptions {
runtimeUrl: string;
autoScrollIntoView: boolean;
render: () => HTMLDivElement;
moveableOptions: MoveableOptions | ((core?: StageCore) => MoveableOptions);
canSelect: (el: HTMLElement) => boolean | Promise<boolean>;
updateDragEl: (el: HTMLDivElement) => void;
}
export interface StoreState {
root: MApp | null;
page: MPage | null;

View File

@ -48,7 +48,7 @@ export default class StageDragResize extends EventEmitter {
/** 目标节点 */
public target?: HTMLElement;
/** 目标节点在蒙层中的占位节点 */
public dragEl: HTMLElement;
public dragEl: HTMLDivElement;
/** Moveable拖拽类实例 */
public moveable?: Moveable;
/** 水平参考线 */
@ -87,10 +87,9 @@ export default class StageDragResize extends EventEmitter {
const oldTarget = this.target;
this.target = el;
this.init(el);
// 从不能拖动到能拖动的节点之间切换要重新创建moveable不然dragStart不生效
if (!this.moveable || this.target !== oldTarget) {
this.init(el);
this.moveableHelper = MoveableHelper.create({
useBeforeRender: true,
useRender: false,
@ -430,6 +429,10 @@ export default class StageDragResize extends EventEmitter {
`;
this.dragEl.id = `${DRAG_EL_ID_PREFIX}${el.id}`;
if (typeof this.core.config.updateDragEl === 'function') {
this.core.config.updateDragEl(this.dragEl, el);
}
}
private destroyDragEl(): void {

View File

@ -41,6 +41,7 @@ export default class StageHighlight extends EventEmitter {
parent: this.core.mask.content,
mask: this.core.mask,
dr: this.core.dr,
core: this.core,
});
}

View File

@ -20,6 +20,7 @@
import { EventEmitter } from 'events';
import { Mode } from './const';
import StageCore from './StageCore';
import StageDragResize from './StageDragResize';
import StageMask from './StageMask';
import type { Offset, TargetCalibrateConfig } from './types';
@ -32,7 +33,8 @@ export default class TargetCalibrate extends EventEmitter {
public parent: HTMLElement;
public mask: StageMask;
public dr: StageDragResize;
public operationEl: HTMLElement;
public core: StageCore;
public operationEl: HTMLDivElement;
constructor(config: TargetCalibrateConfig) {
super();
@ -40,6 +42,7 @@ export default class TargetCalibrate extends EventEmitter {
this.parent = config.parent;
this.mask = config.mask;
this.dr = config.dr;
this.core = config.core;
this.operationEl = globalThis.document.createElement('div');
this.parent.append(this.operationEl);
@ -58,6 +61,11 @@ export default class TargetCalibrate extends EventEmitter {
`;
this.operationEl.id = `${prefix}${el.id}`;
if (typeof this.core.config.updateDragEl === 'function') {
this.core.config.updateDragEl(this.operationEl, el);
}
return this.operationEl;
}

View File

@ -39,6 +39,7 @@ export type StageCoreConfig = {
runtimeUrl?: string;
render?: (renderer: StageCore) => Promise<HTMLElement> | HTMLElement;
autoScrollIntoView?: boolean;
updateDragEl?: (el: HTMLDivElement, target: HTMLElement) => void;
};
export interface StageRenderConfig {
@ -133,4 +134,5 @@ export interface TargetCalibrateConfig {
parent: HTMLElement;
mask: StageMask;
dr: StageDragResize;
core: StageCore;
}