123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 |
- <template>
- <div
- class="component-wrapper"
- ref="componentWrapperRef"
- :style="warpperStyle"
- >
- <div class="component-content" @click="handleSelectComponent">
- <component :is="component" v-bind="componentData.props" />
- </div>
- <div v-if="showEditBox" class="edit-box" :style="editWapperStyle">
- <UseDraggable
- v-for="item in dragPointList"
- :key="item"
- @move="(_, e) => handleDragPoint(item, e)"
- @start="handleDragStart"
- @end="handleDragEnd"
- >
- <span class="edit-box-point" :class="item"></span>
- </UseDraggable>
- </div>
- </div>
- </template>
- <script setup lang="ts">
- import { defineProps, defineAsyncComponent, computed, ref } from "vue";
- import componentAll from "@/components";
- import type { CustomElement } from "#/project";
- import { useStageStore } from "@/store/modules/stage";
- import { useProjectStore } from "@/store/modules/project";
- import { useDraggable } from "@vueuse/core";
- import { UseDraggable } from "@vueuse/components";
- const { componentData } = defineProps<{ componentData: CustomElement }>();
- // 动态引入组件
- const component = defineAsyncComponent(
- componentAll[componentData.componentType]
- );
- const componentWrapperRef = ref<HTMLElement | null>(null);
- const stageStore = useStageStore();
- const projectStore = useProjectStore();
- const editWapperStyle = computed(() => {
- const { width = 400, height = 260 } = componentData.props || {};
- return {
- transform: `scale(${1 / stageStore.scale})`,
- transformOrigin: "50% 50%",
- width: `${width * stageStore.scale}px`,
- height: `${height * stageStore.scale}px`,
- border: "1px solid #1890ff",
- left: (width / 2) * (1 - stageStore.scale) + "px",
- top: (height / 2) * (1 - stageStore.scale) + "px",
- };
- });
- const warpperStyle = computed(() => {
- const { width = 400, height = 260 } = componentData.props || {};
- const { position } = componentData || {};
- return {
- width: `${width}px`,
- height: `${height}px`,
- left: position.x + "px",
- top: position.y + "px",
- };
- });
- // 是否显示编辑框
- const showEditBox = computed(() => {
- return (
- projectStore.mode === "edit" &&
- projectStore.selectedElementKeys.includes(componentData.key)
- );
- });
- let isPointDragFlag = false;
- // 拖拽移动组件
- useDraggable(componentWrapperRef, {
- onMove: (position) => {
- if(isPointDragFlag) return;
- const originPosition = componentWrapperRef.value!.getBoundingClientRect();
- // 计算移动的距离
- const x = position.x - originPosition.left;
- const y = position.y - originPosition.top;
- projectStore.updateElement(componentData.key, {
- position: {
- x: componentData.position.x + x,
- y: componentData.position.y + y,
- },
- });
- },
- onStart: () => {
- projectStore.setSelectedElementKeys([componentData.key]);
- }
- });
- const handleSelectComponent = () => {
- projectStore.setSelectedElementKeys([componentData.key]);
- };
- /* ===============================缩放组件==================================== */
- const dragPointList = [
- "top-left",
- "top-center",
- "top-right",
- "left-center",
- "right-center",
- "bottom-left",
- "bottom-center",
- "bottom-right",
- ];
- const startPoint = {
- x: 0,
- y: 0,
- };
- // 拖拽点移动
- const handleDragPoint = (type: string, e: PointerEvent) => {
- const moveX = (e.x - startPoint.x) / stageStore.scale;
- const moveY = (e.y - startPoint.y) / stageStore.scale;
-
- let width = componentData.props.width;
- let height = componentData.props.height;
- let x = componentData.position.x;
- let y = componentData.position.y;
- switch (type) {
- case "top-left":
- width -= moveX;
- height -= moveY;
- x += moveX;
- y += moveY;
- break;
- case "top-center":
- height -= moveY;
- y += moveY;
- break;
- case "top-right":
- width += moveX;
- height -= moveY;
- y += moveY;
- break;
- case "left-center":
- width -= moveX;
- x += moveX;
- break;
- case "right-center":
- width += moveX;
- break;
- case "bottom-left":
- width -= moveX;
- height += moveY;
- x += moveX;
- break;
- case "bottom-center":
- height += moveY;
- break;
- case "bottom-right":
- width += moveX;
- height += moveY;
- break;
- }
- startPoint.x = e.x;
- startPoint.y = e.y;
- if(width < 10 || height < 10) return;
- projectStore.updateElement(componentData.key, {
- position: { x, y },
- props: {
- ...componentData.props,
- width,
- height,
- },
- });
- };
- // 拖拽点开始
- const handleDragStart = (_, e: PointerEvent) => {
- startPoint.x = e.x;
- startPoint.y = e.y;
- isPointDragFlag = true;
- };
- // 拖拽点结束
- const handleDragEnd = () => {
- isPointDragFlag = false;
- };
- </script>
- <style lang="less" scoped>
- .component-wrapper {
- position: absolute;
- }
- .component-content {
- position: absolute;
- width: 100%;
- height: 100%;
- left: 0;
- top: 0;
- }
- .edit-box {
- position: absolute;
- &-point {
- position: absolute;
- width: 8px;
- height: 8px;
- background: #fff;
- border-radius: 50%;
- border: solid 1px @primary-color;
- }
- .top-left {
- top: -4px;
- left: -4px;
- cursor: nw-resize;
- }
- .top-center {
- top: -4px;
- left: 50%;
- transform: translateX(-50%);
- transform-origin: center;
- cursor: n-resize;
- }
- .top-right {
- top: -4px;
- right: -4px;
- cursor: ne-resize;
- }
- .left-center {
- top: 50%;
- left: -4px;
- transform: translateY(-50%);
- cursor: w-resize;
- }
- .right-center {
- top: 50%;
- right: -4px;
- transform: translateY(-50%);
- cursor: e-resize;
- }
- .bottom-left {
- bottom: -4px;
- left: -4px;
- cursor: sw-resize;
- }
- .bottom-center {
- bottom: -4px;
- left: 50%;
- transform: translateX(-50%);
- cursor: s-resize;
- }
- .bottom-right {
- bottom: -4px;
- right: -4px;
- cursor: se-resize;
- }
- }
- </style>
|