Compare commits
8 Commits
57020eb9ca
...
stage
| Author | SHA1 | Date | |
|---|---|---|---|
| c6484c4b30 | |||
| 8424202fc8 | |||
| e424ea63ec | |||
| be5667057e | |||
| 0c99073376 | |||
| 081dd1327a | |||
| f7a4a80a23 | |||
| 36220bbb02 |
@ -45,9 +45,9 @@
|
||||
group="designer"
|
||||
ghost-class="ghost"
|
||||
class="canvas"
|
||||
@start="onPreviewStart"
|
||||
@update="onPreviewUpdate"
|
||||
@stop="onPreviewStop"
|
||||
@add="onPreViewAdd"
|
||||
>
|
||||
<DynamicComponent v-for="component in store.previewScheme" :key="component.id" :componentData="component">
|
||||
{{ component.id }}
|
||||
@ -156,16 +156,20 @@ function clone(element: Record<'name' | 'id' | 'type' | 'props' | 'class' | 'tex
|
||||
};
|
||||
}
|
||||
|
||||
const onEnd = (event: DraggableEvent) => {
|
||||
console.log("onEnd", event);
|
||||
const onPreViewAdd = (event: DraggableEvent) => {
|
||||
console.log("onPreViewAdd", event);
|
||||
store.updateNowScheme(event.clonedData);
|
||||
};
|
||||
const onEnd = (event: DraggableEvent) => {
|
||||
// console.log("onEnd", event);
|
||||
// store.updateNowScheme(event.clonedData);
|
||||
};
|
||||
|
||||
const onStart = (event) => {
|
||||
// console.log("onStart", event);
|
||||
};
|
||||
|
||||
const onPreviewStart = (event) => {
|
||||
const onPreviewStart = (event:DraggableEvent) => {
|
||||
// console.log("onPreviewStart", event);
|
||||
};
|
||||
|
||||
@ -173,7 +177,7 @@ const onPreviewUpdate = (event) => {
|
||||
// console.log("onPreviewUpdate", event);
|
||||
};
|
||||
|
||||
const onPreviewStop = (event) => {
|
||||
const onPreviewStop = (event:DraggableEvent) => {
|
||||
// console.log(event);
|
||||
};
|
||||
|
||||
|
||||
@ -12,10 +12,16 @@
|
||||
@mouseover="isHovered = true"
|
||||
@mouseleave="isHovered = false"
|
||||
>
|
||||
<div v-if="isHovered" class="component-header">
|
||||
<span>{{componentName}}</span>
|
||||
</div>
|
||||
<div v-if="componentSelected" class="component-header" :style="headerStyle">
|
||||
<span>{{ componentName }}</span>
|
||||
<button style="color: #1057CC" @click="handleEditFunc">编辑</button>
|
||||
<button style="color: #1057CC" @click="handleDeleteFunc">删除</button>
|
||||
<div style="background-color:#3457cc;color: #ffffff;padding: 5px ;margin-right: 2px">{{ componentName }}</div>
|
||||
<div v-if="componentSelected" style="background-color:#3457cc;color:#ffffff;padding: 6px 5px 5px 5px;display: flex;width: fit-content;flex-wrap: nowrap">
|
||||
<icon-copy class="clickable" size="20" />
|
||||
<icon-edit class="clickable" @click="handleEditFunc" size="20"/>
|
||||
<icon-delete class="clickable" @click="handleDeleteFunc" size="20"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="component-content">
|
||||
<component
|
||||
@ -103,6 +109,7 @@ const adjustHeaderPosition = () => {
|
||||
|
||||
let top = 0;
|
||||
let left = 0;
|
||||
let justification='';
|
||||
|
||||
// 获取最外层组件渲染区域的边界
|
||||
const containerEl = document.getElementById('renderArea');
|
||||
@ -110,34 +117,35 @@ const adjustHeaderPosition = () => {
|
||||
|
||||
const containerRect = containerEl.getBoundingClientRect();
|
||||
|
||||
debugger
|
||||
// 计算上下左右的可用空间
|
||||
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;
|
||||
}
|
||||
top = -headerRect.height+2;
|
||||
|
||||
} else if (bottomSpace >= headerRect.height) {
|
||||
top = componentRect.height-2;
|
||||
}
|
||||
if (headerRect.width>componentRect.width)
|
||||
{
|
||||
left=-2;
|
||||
justification='flex-start';
|
||||
}else
|
||||
{
|
||||
left=componentRect.width-headerRect.width-2;
|
||||
justification='flex-end';
|
||||
}
|
||||
headerStyle.value = {
|
||||
top: `${top}px`,
|
||||
left: `${left}px`
|
||||
left: `${left}px`,
|
||||
justifyContent: justification
|
||||
};
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
adjustHeaderPosition()
|
||||
// console.log("组件挂载后",props.componentData);
|
||||
});
|
||||
|
||||
@ -159,21 +167,20 @@ watch(() => componentSelected.value, () => {
|
||||
}
|
||||
|
||||
.dynamic-component.hover-state {
|
||||
border: 1px dashed #1057CC; /* 悬停时浅蓝色虚线框 */
|
||||
border: 1px dashed #3457cc; /* 悬停时浅蓝色虚线框 */
|
||||
}
|
||||
|
||||
.dynamic-component.click-state {
|
||||
border: 2px solid #1057CC; /* 点击时深蓝色实线框 */
|
||||
border: 2px solid #3457cc; /* 点击时深蓝色实线框 */
|
||||
}
|
||||
|
||||
.component-header {
|
||||
position: absolute;
|
||||
color: #1057CC;
|
||||
padding: 5px;
|
||||
color: #3457cc;
|
||||
display: flex;
|
||||
flex-wrap: nowrap; /* 禁止换行 */
|
||||
align-content: center;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
z-index: 1000;
|
||||
background-color: transparent; /* 确保没有背景颜色 */
|
||||
box-sizing: border-box; /* 确保内边距不会影响宽度 */
|
||||
@ -186,7 +193,7 @@ watch(() => componentSelected.value, () => {
|
||||
.component-header button {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
color: #1057CC;
|
||||
color: #3457cc;
|
||||
cursor: pointer;
|
||||
margin-left: 10px;
|
||||
}
|
||||
@ -200,4 +207,8 @@ watch(() => componentSelected.value, () => {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.clickable {
|
||||
cursor: pointer; /* 当鼠标悬停在此元素上时,鼠标指针变为手形 */
|
||||
}
|
||||
</style>
|
||||
@ -1,30 +1,17 @@
|
||||
import {defineStore} from 'pinia';
|
||||
import {IPageComponent} from '@/type/IPageComponent';
|
||||
import {sha256} from 'js-sha256';
|
||||
import { defineStore } from 'pinia';
|
||||
import { IPageComponent } from '@/type/IPageComponent';
|
||||
import { sha256 } from 'js-sha256';
|
||||
import { popFromStack, pushToStack, topFromStack } from '@/utils/LRU.ts';
|
||||
|
||||
// 缓存对象
|
||||
const idToObjectCache = new Map<string, IPageComponent>();
|
||||
|
||||
// 栈维护函数
|
||||
function pushToStack(stack: string[], id: string): void {
|
||||
if (!stack.includes(id)) {
|
||||
stack.push(id);
|
||||
}
|
||||
}
|
||||
|
||||
function popFromStack(stack: string[]): string | undefined {
|
||||
return stack.pop();
|
||||
}
|
||||
function topFromStack(stack: string[]): string | undefined {
|
||||
return stack.at(-1); // 使用 .at() 方法访问最后一个元素
|
||||
}
|
||||
|
||||
function findObjectById(obj: any, targetId: string) {
|
||||
if (Array.isArray(obj)) {
|
||||
for (let i = 0; i < obj.length; i++) {
|
||||
const item = obj[i];
|
||||
if (item.id === targetId) {
|
||||
return {item, index: i, parent: obj};
|
||||
return { item, index: i, parent: obj };
|
||||
}
|
||||
const found = findObjectById(item, targetId);
|
||||
if (found) return found;
|
||||
@ -93,38 +80,30 @@ export const useSchemeStore = defineStore('scheme', {
|
||||
},
|
||||
|
||||
updateNowScheme(updates: Partial<IPageComponent>) {
|
||||
// debugger;
|
||||
this.nowComponentsData = updates;
|
||||
pushToStack(this.selectedComponentStack, this.nowComponentsData.id);
|
||||
|
||||
console.log("更新nowComponentsData",this.nowComponentsData);
|
||||
|
||||
console.log("更新selectedComponentStack",this.selectedComponentStack);
|
||||
console.log("更新nowComponentsData", this.nowComponentsData);
|
||||
|
||||
return this.nowComponentsData;
|
||||
},
|
||||
deleteScheme(id: string) {
|
||||
console.log("删除前,组件id",id)
|
||||
console.log("删除前,栈",this.selectedComponentStack)
|
||||
// debugger;
|
||||
console.log("删除前,组件id", id);
|
||||
const currentStateHash = this.currentHash;
|
||||
const objToDelete = findObjectById(this.previewScheme, id);
|
||||
if (objToDelete) {
|
||||
const {item, index, parent} = objToDelete;
|
||||
const { item, index, parent } = objToDelete;
|
||||
parent.splice(index, 1);
|
||||
idToObjectCache.delete(id); // 从缓存中删除
|
||||
// 清理 history 中的引用
|
||||
this.cleanupReferences(id);
|
||||
|
||||
}
|
||||
this.saveNewState(currentStateHash);
|
||||
popFromStack(this.selectedComponentStack);
|
||||
console.log("scheme",this.previewScheme);
|
||||
const preComponentId=topFromStack(this.selectedComponentStack)
|
||||
console.log("删除后,栈",this.selectedComponentStack)
|
||||
console.log("删除后,前一个组件id",preComponentId)
|
||||
const preObj=this.getSchemeObj(preComponentId)
|
||||
console.log("删除后,前一个组件",preObj)
|
||||
|
||||
this.nowComponentsData = preObj;
|
||||
const preComponentId = topFromStack(this.selectedComponentStack);
|
||||
this.nowComponentsData = this.getSchemeObj(preComponentId || '');
|
||||
},
|
||||
cleanupReferences(id: string) {
|
||||
// 清理 nowComponentsData
|
||||
@ -138,7 +117,7 @@ export const useSchemeStore = defineStore('scheme', {
|
||||
if (historyState) {
|
||||
const obj = findObjectById(historyState, id);
|
||||
if (obj) {
|
||||
const {parent, index} = obj;
|
||||
const { parent, index } = obj;
|
||||
parent.splice(index, 1);
|
||||
}
|
||||
}
|
||||
@ -150,7 +129,7 @@ export const useSchemeStore = defineStore('scheme', {
|
||||
const prevState = this.history[this.currentIndex % HISTORY_LENGTH];
|
||||
if (prevState) {
|
||||
this.previewScheme = prevState;
|
||||
this.nowComponentsData = this.previewScheme[0] || {} as IPageComponent;
|
||||
this.nowComponentsData = this.getSchemeObj(topFromStack(this.selectedComponentStack) || '');
|
||||
this.currentHash = sha256(JSON.stringify(this.previewScheme));
|
||||
}
|
||||
}
|
||||
@ -161,7 +140,7 @@ export const useSchemeStore = defineStore('scheme', {
|
||||
const nextState = this.history[this.currentIndex % HISTORY_LENGTH];
|
||||
if (nextState) {
|
||||
this.previewScheme = nextState;
|
||||
this.nowComponentsData = this.previewScheme[0] || {} as IPageComponent;
|
||||
this.nowComponentsData = this.getSchemeObj(topFromStack(this.selectedComponentStack) || '');
|
||||
this.currentHash = sha256(JSON.stringify(this.previewScheme));
|
||||
}
|
||||
}
|
||||
|
||||
15
src/utils/LRU.ts
Normal file
15
src/utils/LRU.ts
Normal file
@ -0,0 +1,15 @@
|
||||
export function pushToStack(stack: string[], id: string): void {
|
||||
if (stack.includes(id)) {
|
||||
// 如果已经存在于栈中,先移除再插入到栈顶
|
||||
stack.splice(stack.indexOf(id), 1);
|
||||
}
|
||||
stack.push(id);
|
||||
}
|
||||
|
||||
export function popFromStack(stack: string[]): string | undefined {
|
||||
return stack.pop();
|
||||
}
|
||||
|
||||
export function topFromStack(stack: string[]): string | undefined {
|
||||
return stack.at(-1); // 使用 .at() 方法访问最后一个元素
|
||||
}
|
||||
Reference in New Issue
Block a user