vue3.x + vite2.x + vant + element-plus H5移动端低代码平台 lowcode 可视化拖拽 可视化编辑器 visual editor 类似易企秀的H5制作、建站工具、可视化搭建工具
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

152 lines
3.8 KiB

<template>
<draggable-transition-group
v-model="slotChildren"
v-model:drag="isDrag"
class="inner-draggable"
:class="{ slot: !slotChildren?.length }"
draggable=".item-drag"
:data-slot="`插槽(${slotKey})\n 拖拽组件到此处`"
>
<template #item="{ element: innerElement }">
<div
class="list-group-item inner"
:data-label="innerElement.label"
:class="{
focus: innerElement.focus,
focusWithChild: innerElement.focusWithChild,
}"
@contextmenu.stop.prevent="onContextmenuBlock($event, innerElement, slotChildren)"
@mousedown.stop="selectComp(innerElement)"
>
<comp-render
:element="innerElement"
:style="{
pointerEvents: Object.keys(innerElement.props?.slots || {}).length ? 'auto' : 'none',
}"
>
<template v-for="(value, key) in innerElement.props?.slots" :key="key" #[key]>
<SlotItem
v-model:children="value.children"
v-model:drag="isDrag"
:slot-key="key"
:on-contextmenu-block="onContextmenuBlock"
:select-comp="selectComp"
/>
</template>
</comp-render>
</div>
</template>
</draggable-transition-group>
</template>
<script lang="ts">
/**
* @name: slot-item
* @author:卜启缘
* @date: 2021/5/2 22:36
* @descriptionslot-item
* @update: 2021/5/2 22:36
*/
import { defineComponent, PropType } from 'vue';
import { useVModel } from '@vueuse/core';
import DraggableTransitionGroup from './draggable-transition-group.vue';
import CompRender from './comp-render';
import type { VisualEditorBlockData } from '@/visual-editor/visual-editor.utils';
export default defineComponent({
name: 'SlotItem',
components: { CompRender, DraggableTransitionGroup },
props: {
slotKey: {
type: String as PropType<string | number>,
default: '',
},
drag: {
type: Boolean as PropType<boolean>,
default: false,
},
children: {
type: Array as PropType<VisualEditorBlockData[]>,
default: () => [],
},
selectComp: {
type: Function as PropType<(comp: VisualEditorBlockData) => void>,
required: true,
},
onContextmenuBlock: {
type: Function as PropType<
(
e: MouseEvent,
block: VisualEditorBlockData,
parentBlocks?: VisualEditorBlockData[],
) => void
>,
required: true,
},
},
emits: ['update:children', 'on-selected', 'update:drag'],
setup(props, { emit }) {
// 初始化时设置上次选中的组件
props.children.some((item) => item.focus && props.selectComp(item));
return {
isDrag: useVModel(props, 'drag', emit),
slotChildren: useVModel(props, 'children', emit),
};
},
});
</script>
<style lang="scss" scoped>
@import './func.scss';
.inner-draggable {
position: relative;
}
.inner-draggable.slot::after {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
display: flex;
height: auto;
min-height: 40px;
font-size: 12px;
color: #8591a2;
text-align: center;
background: rgba(246, 247, 249, 0.5);
content: attr(data-slot);
outline: 1px dashed #dedede;
outline-offset: -1px;
flex-direction: column;
justify-content: center;
}
.list-group-item {
position: relative;
padding: 3px;
cursor: move;
&.focusWithChild {
@include showContainerBorder;
}
&.focus {
@include showSoliOutline;
&::after {
@include showCompLabel(top);
opacity: 0;
transition: opacity 0.2s;
}
&:hover::after {
opacity: 1;
}
}
}
</style>