feat(editor): 支持拖拽添加组件

This commit is contained in:
roymondchen 2022-05-06 20:02:47 +08:00 committed by jia000
parent 76b8d2314a
commit 5da8601f36
5 changed files with 59 additions and 7 deletions

View File

@ -12,7 +12,14 @@
<template v-for="(group, index) in list">
<el-collapse-item v-if="group.items && group.items.length" :key="index" :name="index">
<template #title><i class="el-icon-s-grid"></i>{{ group.title }}</template>
<div class="component-item" v-for="item in group.items" :key="item.type" @click="appendComponent(item)">
<div
class="component-item"
v-for="item in group.items"
draggable="true"
:key="item.type"
@click="appendComponent(item)"
@dragstart="dragstartHandler(item, $event)"
>
<m-icon :icon="item.icon"></m-icon>
<el-tooltip effect="dark" placement="bottom" :content="item.text">
@ -27,6 +34,7 @@
<script lang="ts">
import { computed, defineComponent, inject, ref } from 'vue';
import serialize from 'serialize-javascript';
import MIcon from '@editor/components/Icon.vue';
import type { ComponentGroup, ComponentItem, Services } from '@editor/type';
@ -63,6 +71,20 @@ export default defineComponent({
...data,
});
},
dragstartHandler({ text, type, data = {} }: ComponentItem, e: DragEvent) {
if (e.dataTransfer) {
e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData(
'data',
serialize({
name: text,
type,
...data,
}).replace(/"(\w+)":\s/g, '$1: '),
);
}
},
};
},
});

View File

@ -9,8 +9,10 @@
<div
class="m-editor-stage-container"
ref="stageContainer"
@contextmenu="contextmenuHandler"
:style="`transform: scale(${zoom})`"
@contextmenu="contextmenuHandler"
@drop="dropHandler"
@dragover="dragoverHandler"
></div>
<teleport to="body">
<viewer-menu ref="menu"></viewer-menu>
@ -39,7 +41,7 @@ import type { MoveableOptions, Runtime, SortEventData, UpdateEventData } from '@
import StageCore from '@tmagic/stage';
import ScrollViewer from '@editor/components/ScrollViewer.vue';
import type { Services, StageRect } from '@editor/type';
import { Layout, Services, StageRect } from '@editor/type';
import ViewerMenu from './ViewerMenu.vue';
@ -188,6 +190,34 @@ export default defineComponent({
e.preventDefault();
menu.value?.show(e);
},
dragoverHandler(e: DragEvent) {
e.preventDefault();
if (e.dataTransfer) {
e.dataTransfer.dropEffect = 'move';
}
},
async dropHandler(e: DragEvent) {
e.preventDefault();
if (e.dataTransfer && page.value && stageContainer.value && stage) {
// eslint-disable-next-line no-eval
const config = eval(`(${e.dataTransfer.getData('data')})`);
const layout = await services?.editorService.getLayout(page.value);
const containerRect = stageContainer.value.getBoundingClientRect();
const { scrollTop, scrollLeft } = stage.mask;
if (layout === Layout.ABSOLUTE) {
config.style = {
position: 'absolute',
top: e.clientY - containerRect.top + scrollTop,
left: e.clientX - containerRect.left + scrollLeft,
};
}
services?.editorService.add(config, page.value);
}
},
};
},
});

View File

@ -17,7 +17,7 @@
*/
import { reactive } from 'vue';
import { cloneDeep } from 'lodash-es';
import { cloneDeep, mergeWith } from 'lodash-es';
import type { FormConfig } from '@tmagic/form';
import type { MComponent, MNode } from '@tmagic/schema';
@ -100,8 +100,7 @@ class Props extends BaseService {
return cloneDeep({
...getDefaultPropsValue(type),
...defaultValue,
...(this.state.propsValueMap[type] || {}),
...mergeWith(this.state.propsValueMap[type] || {}, defaultValue),
});
}
}

View File

@ -63,6 +63,7 @@
color: $--font-color;
flex-direction: column;
width: 42px;
cursor: pointer;
i {
font-size: 20px;

View File

@ -144,7 +144,7 @@ const setTop2Middle = (node: MNode, parentNode: MNode, stage: StageCore) => {
const style = node.style || {};
const height = style.height || 0;
if (!stage || style.top || !parentNode.style || !isNumber(height)) return style;
if (!stage || typeof style.top !== 'undefined' || !parentNode.style || !isNumber(height)) return style;
const { height: parentHeight } = parentNode.style;