mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2025-04-06 03:57:56 +08:00
feat(editor): 支持拖拽添加组件
This commit is contained in:
parent
76b8d2314a
commit
5da8601f36
@ -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: '),
|
||||
);
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
|
@ -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);
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
|
@ -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),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -63,6 +63,7 @@
|
||||
color: $--font-color;
|
||||
flex-direction: column;
|
||||
width: 42px;
|
||||
cursor: pointer;
|
||||
|
||||
i {
|
||||
font-size: 20px;
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user