Compare commits
2 Commits
91aab43ecb
...
402e686d87
| Author | SHA1 | Date | |
|---|---|---|---|
| 402e686d87 | |||
| 116e28b8fa |
@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
|
style="width: fit-content; display: flex; flex-direction: column; position: relative;"
|
||||||
v-if="componentVisible || store.designerMode"
|
v-if="componentVisible || store.designerMode"
|
||||||
:id="componentId"
|
:id="componentId"
|
||||||
:class="[
|
:class="[
|
||||||
@ -11,30 +12,32 @@
|
|||||||
@mouseover="isHovered = true"
|
@mouseover="isHovered = true"
|
||||||
@mouseleave="isHovered = false"
|
@mouseleave="isHovered = false"
|
||||||
>
|
>
|
||||||
<div v-if="isClicked" class="component-header">
|
<div v-if="isClicked" class="component-header" :style="headerStyle">
|
||||||
<span>{{ componentName }}</span>
|
<span>{{ componentName }}</span>
|
||||||
<button @click="handleFunction('edit')">编辑</button>
|
<button style="color: #1057CC" @click="handleFunction('edit')">编辑</button>
|
||||||
<button @click="handleFunction('delete')">删除</button>
|
<button style="color: #1057CC" @click="handleFunction('delete')">删除</button>
|
||||||
|
</div>
|
||||||
|
<div class="component-content">
|
||||||
|
<component
|
||||||
|
:is="componentType"
|
||||||
|
v-bind="componentPropsWithDisabled"
|
||||||
|
:class="componentClass"
|
||||||
|
:style="componentStyle"
|
||||||
|
>
|
||||||
|
{{ componentText }}
|
||||||
|
<template v-for="child in componentChildren" :key="child.id">
|
||||||
|
<DynamicComponent :componentData="child" />
|
||||||
|
</template>
|
||||||
|
<template v-for="(slot, key, index) in componentSlots" :key="index" v-slot:[key]>
|
||||||
|
<DynamicComponent :component-data="slot" />
|
||||||
|
</template>
|
||||||
|
</component>
|
||||||
</div>
|
</div>
|
||||||
<component
|
|
||||||
:is="componentType"
|
|
||||||
v-bind="componentPropsWithDisabled"
|
|
||||||
:class="componentClass"
|
|
||||||
:style="componentStyle"
|
|
||||||
>
|
|
||||||
{{ componentText }}
|
|
||||||
<template v-for="child in componentChildren" :key="child.id">
|
|
||||||
<DynamicComponent :component-data="child" />
|
|
||||||
</template>
|
|
||||||
<template v-for="(slot, key, index) in componentSlots" :key="index" v-slot:[key]>
|
|
||||||
<DynamicComponent :component-data="slot" />
|
|
||||||
</template>
|
|
||||||
</component>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { defineProps, ref, computed, onMounted, watch, markRaw } from 'vue';
|
import { defineProps, ref, computed, onMounted, watch, markRaw, nextTick } from 'vue';
|
||||||
import { componentMapping } from './componentMapping';
|
import { componentMapping } from './componentMapping';
|
||||||
import { useSchemeStore } from '../stores/useSchemeStore';
|
import { useSchemeStore } from '../stores/useSchemeStore';
|
||||||
|
|
||||||
@ -43,10 +46,6 @@ const props = defineProps({
|
|||||||
componentData: Object
|
componentData: Object
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
console.log(props.componentData);
|
|
||||||
});
|
|
||||||
|
|
||||||
const componentId = computed(() => props.componentData?.id || '');
|
const componentId = computed(() => props.componentData?.id || '');
|
||||||
const componentName = computed(() => props.componentData?.name || 'Unnamed Component');
|
const componentName = computed(() => props.componentData?.name || 'Unnamed Component');
|
||||||
const componentType = computed(() => markRaw(componentMapping[props.componentData?.type]) || 'div');
|
const componentType = computed(() => markRaw(componentMapping[props.componentData?.type]) || 'div');
|
||||||
@ -85,6 +84,69 @@ const handleFunction = (action: string) => {
|
|||||||
console.log(`Action: ${action}`);
|
console.log(`Action: ${action}`);
|
||||||
// 处理编辑或删除操作
|
// 处理编辑或删除操作
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const headerStyle = ref({});
|
||||||
|
|
||||||
|
const targetContent = ref<HTMLElement | null>(null);
|
||||||
|
|
||||||
|
const adjustHeaderPosition = () => {
|
||||||
|
const componentEl = document.getElementById(componentId.value);
|
||||||
|
if (!componentEl) return;
|
||||||
|
|
||||||
|
const headerEl = componentEl.querySelector('.component-header');
|
||||||
|
if (!headerEl) return;
|
||||||
|
|
||||||
|
const componentRect = componentEl.getBoundingClientRect();
|
||||||
|
const headerRect = headerEl.getBoundingClientRect();
|
||||||
|
|
||||||
|
let top = 0;
|
||||||
|
let left = 0;
|
||||||
|
|
||||||
|
// 获取最外层组件渲染区域的边界
|
||||||
|
const containerEl = targetContent.value;
|
||||||
|
if (!containerEl) return;
|
||||||
|
|
||||||
|
const containerRect = containerEl.getBoundingClientRect();
|
||||||
|
|
||||||
|
// 计算上下左右的可用空间
|
||||||
|
const topSpace = componentRect.top - containerRect.top;
|
||||||
|
const bottomSpace = containerRect.bottom - componentRect.bottom;
|
||||||
|
const leftSpace = componentRect.left - containerRect.left;
|
||||||
|
const rightSpace = containerRect.right - componentRect.right;
|
||||||
|
|
||||||
|
// 检查上方是否有足够的空间
|
||||||
|
if (topSpace >= headerRect.height) {
|
||||||
|
top = -headerRect.height - 10;
|
||||||
|
left = rightSpace >= headerRect.width ? componentRect.width - headerRect.width : 0;
|
||||||
|
} else if (bottomSpace >= headerRect.height) {
|
||||||
|
top = componentRect.height + 10;
|
||||||
|
left = rightSpace >= headerRect.width ? componentRect.width - headerRect.width : 0;
|
||||||
|
} else if (leftSpace >= headerRect.width) {
|
||||||
|
left = -headerRect.width - 10;
|
||||||
|
top = 0;
|
||||||
|
} else if (rightSpace >= headerRect.width) {
|
||||||
|
left = componentRect.width + 10;
|
||||||
|
top = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
headerStyle.value = {
|
||||||
|
top: `${top}px`,
|
||||||
|
left: `${left}px`
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
console.log(props.componentData);
|
||||||
|
adjustHeaderPosition();
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(() => isClicked.value, () => {
|
||||||
|
if (isClicked.value) {
|
||||||
|
nextTick(() => {
|
||||||
|
adjustHeaderPosition();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@ -92,6 +154,7 @@ const handleFunction = (action: string) => {
|
|||||||
position: relative;
|
position: relative;
|
||||||
border: 1px solid transparent; /* 默认透明边框 */
|
border: 1px solid transparent; /* 默认透明边框 */
|
||||||
transition: border 0.3s, box-shadow 0.3s;
|
transition: border 0.3s, box-shadow 0.3s;
|
||||||
|
width: fit-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dynamic-component.hover-state {
|
.dynamic-component.hover-state {
|
||||||
@ -104,17 +167,15 @@ const handleFunction = (action: string) => {
|
|||||||
|
|
||||||
.component-header {
|
.component-header {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
color: #1057CC;
|
||||||
left: 0;
|
|
||||||
background-color: rgba(0, 0, 0, 0.8);
|
|
||||||
color: white;
|
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
border-radius: 4px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
|
background-color: transparent; /* 确保没有背景颜色 */
|
||||||
|
box-sizing: border-box; /* 确保内边距不会影响宽度 */
|
||||||
}
|
}
|
||||||
|
|
||||||
.component-header span {
|
.component-header span {
|
||||||
@ -124,7 +185,7 @@ const handleFunction = (action: string) => {
|
|||||||
.component-header button {
|
.component-header button {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
border: none;
|
border: none;
|
||||||
color: white;
|
color: #1057CC;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
@ -132,4 +193,10 @@ const handleFunction = (action: string) => {
|
|||||||
.component-header button:hover {
|
.component-header button:hover {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.component-content {
|
||||||
|
flex-grow: 1;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
Reference in New Issue
Block a user