mirror of
				https://github.com/Tencent/tmagic-editor.git
				synced 2025-11-04 02:28:04 +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