Skip to content

Commit c654ee9

Browse files
committed
refactor(StageStore): 重构移动组件逻辑并提取公共方法
将移动组件的逻辑进行重构,提取出计算受影响组件的公共方法 `_calcEffectedElementsOfMoved`,以提高代码的可维护性和复用性。同时优化了组件移动时的处理流程,确保组件在移动后能够正确更新其组合关系。
1 parent 04b120d commit c654ee9

File tree

4 files changed

+181
-80
lines changed

4 files changed

+181
-80
lines changed

src/components/ui/left/tree/ElementsTree.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
<script lang="ts" setup>
5656
import { useStageStore } from "@/stores/stage";
5757
import { CreatorIcons } from "@/types/CreatorDicts";
58-
import { ElementTreeNode } from "@/types/IElement";
58+
import { ElementTreeNode, TreeNodeDropType } from "@/types/IElement";
5959
import { TreeInstance } from "element-plus";
6060
import type Node from "element-plus/es/components/tree/src/model/node";
6161
import type { DragEvents } from "element-plus/es/components/tree/src/model/useDragNode";
@@ -111,7 +111,7 @@ const handleDragEnd = (draggingNode: Node, dropNode: Node, dropType: NodeDropTyp
111111
console.log("tree drag end:", dropNode && dropNode.label, dropType);
112112
};
113113
const handleDrop = (draggingNode: Node, dropNode: Node, dropType: NodeDropType, ev: DragEvents) => {
114-
stageStore.moveElementsTo([draggingNode.data.id], dropNode.data.id, dropType);
114+
stageStore.moveElementsTo([draggingNode.data.id], dropNode.data.id, TreeNodeDropType[dropType]);
115115
console.log("tree drop:", dropNode.label, dropType);
116116
};
117117
const allowDrop = (draggingNode: Node, dropNode: Node, type: AllowDropType) => {

src/modules/stage/StageShield.ts

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2305,7 +2305,7 @@ export default class StageShield extends DrawerBase implements IStageShield, ISt
23052305
);
23062306
if (group) {
23072307
this._clearStageSelects();
2308-
this.store.selectElement(group);
2308+
this.store.setElementsDetachedSelected([group.id], true);
23092309
}
23102310
const command = await CommandHelper.createElementsChangedCommand(uDataList.reverse(), rDataList, ElementCommandTypes.GroupAdded, this.store);
23112311
if (command) {
@@ -2691,29 +2691,35 @@ export default class StageShield extends DrawerBase implements IStageShield, ISt
26912691

26922692
/**
26932693
* 设置组件选中状态(组件脱离组合的独立选中状态切换)
2694-
*
2695-
* @param ids
2696-
* @param isDetachedSelected
2694+
*
2695+
* @param ids
2696+
* @param isDetachedSelected
26972697
*/
26982698
setElementsDetachedSelected(ids: string[], isDetachedSelected: boolean): void {
26992699
this.store.setElementsDetachedSelected(ids, isDetachedSelected);
27002700
}
27012701

27022702
/**
27032703
* 移动组件到指定位置
2704-
*
2705-
* @param ids
2706-
* @param target
2704+
*
2705+
* @param ids
2706+
* @param target
27072707
* @param dropType
27082708
*/
27092709
async moveElementsTo(ids: string[], target: string, dropType: TreeNodeDropType): Promise<void> {
27102710
const uDataList: Array<ICommandElementObject> = [];
27112711
const rDataList: Array<ICommandElementObject> = [];
2712-
await this.store.moveElementsTo(ids, target, dropType, async (actionParams: ElementsActionParam[]) => {
2713-
uDataList.push(...(await CommandHelper.createDataListByActionParams(actionParams)));
2714-
}, async (actionParams: ElementsActionParam[]) => {
2715-
rDataList.push(...(await CommandHelper.createDataListByActionParams(actionParams)));
2716-
});
2712+
await this.store.moveElementsTo(
2713+
ids,
2714+
target,
2715+
dropType,
2716+
async (actionParams: ElementsActionParam[]) => {
2717+
uDataList.push(...(await CommandHelper.createDataListByActionParams(actionParams)));
2718+
},
2719+
async (actionParams: ElementsActionParam[]) => {
2720+
rDataList.push(...(await CommandHelper.createDataListByActionParams(actionParams)));
2721+
},
2722+
);
27172723
const command = await CommandHelper.createElementsChangedCommand(uDataList.reverse(), rDataList, ElementCommandTypes.ElementsMoved, this.store);
27182724
if (command) {
27192725
this.undoRedo.add(command);

src/modules/stage/StageStore.ts

Lines changed: 155 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -2523,52 +2523,51 @@ export default class StageStore implements IStageStore {
25232523
}
25242524

25252525
/**
2526-
* 将选中的组件转换为组合
2527-
*
2528-
* 处理组件的流程如下:
2529-
*
2530-
* 1. 将被选中的组件移动到被选中的层级最高的组件之前
2531-
* 2. 查找需要删除和更新的组合
2532-
* 3. 在层级最高的组件后插入新的组合
2533-
* 4. 删除或者更新需要删除和更新的组合
2526+
* 计算移动组件位置时,受影响的组件
25342527
*
25352528
* @param elements
2529+
* @param targetElementGroup
2530+
* @param targetElementGroupAncestors
2531+
* @returns
25362532
*/
2537-
async createElementGroup(elements: IElement[], undoActionCallback: ElementActionCallback, redoActionCallback: ElementActionCallback): Promise<IElementGroup> {
2538-
if (elements.length < 1) return;
2539-
// 组合id集合
2540-
const elementIds: string[] = elements.map(element => element.id);
2541-
// 对给定的组件所属的链表节点进行重新排序
2542-
const sortedElements = this.sortElements(elements);
2543-
// 找到给定组件的层级最高的组件,我们将要把组合组件插入到这个组件之后
2544-
const targetElement = sortedElements[sortedElements.length - 1];
2545-
// 目标组件所属的组合
2546-
const targetElementGroup = targetElement.group;
2547-
// 目标组件所属的组合的祖先组件
2548-
const targetElementGroupAncestors = targetElementGroup?.ancestorGroups;
2549-
// 目标组件在目标组件所属的组合中的索引
2550-
let targetIndexOfGroupSubs = -1;
2551-
// 计算目标组件在目标组件所属的组合中的索引
2552-
targetIndexOfGroupSubs = targetElementGroup?.model.subIds.indexOf(targetElement.id);
2533+
private _calcEffectedElementsOfMoved(
2534+
elements: IElement[],
2535+
targetElementGroup: IElementGroup,
2536+
targetElementGroupAncestors: IElementGroup[],
2537+
): {
2538+
actionParams: ElementsActionParam[];
2539+
removedGroups: IElementGroup[];
2540+
updatedGroups: IElementGroup[];
2541+
outerLayerIdSet: Set<string>;
2542+
elementIdSet: Set<string>;
2543+
updatedGroupIdSet: Set<string>;
2544+
removedGroupIdSet: Set<string>;
2545+
} {
2546+
// 组件id集合
2547+
const elementIdSet: Set<string> = new Set();
2548+
elements.forEach(element => {
2549+
elementIdSet.add(element.id);
2550+
});
25532551
// 需要删除或者更新的组合
25542552
const groupIdSet: Set<string> = new Set();
25552553
// 需要删除的组合id集合,用于后续删除组合
25562554
const removedGroupIdSet: Set<string> = new Set();
25572555
// 需要更新的组合id集合,用于后续更新组合
25582556
const updatedGroupIdSet: Set<string> = new Set();
2559-
// 当前给定组件中的非子组件id集合
2560-
const nonSubIdSet: Set<string> = new Set();
2557+
// 外层组件id集合
2558+
const outerLayerIdSet: Set<string> = new Set();
25612559
// 组合添加之前的回调函数的参数
25622560
const actionParams: ElementsActionParam[] = [];
25632561
// 找到需要删除或者更新的组合
25642562
elements.forEach(element => {
25652563
if (element.isGroupSubject) {
2566-
if (!element.group.isSelected) {
2567-
groupIdSet.add(element.model.groupId);
2568-
nonSubIdSet.add(element.id);
2564+
const groupId = element.model.groupId;
2565+
if (!elementIdSet.has(groupId)) {
2566+
groupIdSet.add(groupId);
2567+
outerLayerIdSet.add(element.id);
25692568
}
25702569
} else {
2571-
nonSubIdSet.add(element.id);
2570+
outerLayerIdSet.add(element.id);
25722571
}
25732572
// 标记需要移动位置的组件
25742573
actionParams.push({
@@ -2578,21 +2577,12 @@ export default class StageStore implements IStageStore {
25782577
});
25792578
// 获取排序后的组合集合
25802579
const groups: IElement[] = this.getOrderedElementsByIds(Array.from(groupIdSet));
2581-
// 顶层组合集合
2582-
const nonSubElements: IElement[] = this.getOrderedElementsByIds(Array.from(nonSubIdSet));
2583-
2584-
/**
2585-
* 判断是否需要删除组合
2586-
*
2587-
* @param group
2588-
* @returns
2589-
*/
2580+
// 判断是否需要删除组合
25902581
function groupShouldRemove(group: IElementGroup): boolean {
25912582
const subIds = group.model.subIds;
25922583
// 如果组合内的所有子组件都在给定的组件集合内,则需要删除组合
2593-
return subIds.every(id => elementIds.includes(id) || subIds.every(id => removedGroupIdSet.has(id))) && group.id !== targetElementGroup?.id && !targetElementGroupAncestors?.includes(group);
2584+
return subIds.every(id => elementIdSet.has(id) || subIds.every(id => removedGroupIdSet.has(id))) && group.id !== targetElementGroup?.id && !targetElementGroupAncestors?.includes(group);
25942585
}
2595-
25962586
// 找到需要删除或者更新的组合
25972587
groups.forEach(group => {
25982588
// 如果组合内的所有子组件都在给定的组件集合内,则需要删除组合
@@ -2614,69 +2604,114 @@ export default class StageStore implements IStageStore {
26142604
});
26152605

26162606
// 获取需要删除的组合
2617-
const removedGroups = this.getOrderedElementsByIds(Array.from(removedGroupIdSet));
2607+
const removedGroups = this.getOrderedElementsByIds(Array.from(removedGroupIdSet)) as IElementGroup[];
26182608
removedGroups.forEach(group => {
26192609
actionParams.push({
26202610
type: ElementActionTypes.Removed,
26212611
data: [group],
26222612
});
26232613
});
26242614
// 获取需要更新的组合
2625-
const updatedGroups = this.getOrderedElementsByIds(Array.from([...updatedGroupIdSet, ...(targetElementGroupAncestors?.map(group => group.id).flat() || [])]));
2615+
const updatedGroups = this.getOrderedElementsByIds(Array.from([...updatedGroupIdSet, ...(targetElementGroupAncestors?.map(group => group.id).flat() || [])])) as IElementGroup[];
26262616
updatedGroups.forEach(group => {
26272617
actionParams.push({
26282618
type: ElementActionTypes.GroupUpdated,
26292619
data: [group],
26302620
});
26312621
});
2622+
return {
2623+
actionParams,
2624+
removedGroups,
2625+
updatedGroups,
2626+
outerLayerIdSet,
2627+
elementIdSet,
2628+
updatedGroupIdSet,
2629+
removedGroupIdSet,
2630+
};
2631+
}
2632+
2633+
/**
2634+
* 将选中的组件转换为组合
2635+
*
2636+
* 处理组件的流程如下:
2637+
*
2638+
* 1. 将被选中的组件移动到被选中的层级最高的组件之前
2639+
* 2. 查找需要删除和更新的组合
2640+
* 3. 在层级最高的组件后插入新的组合
2641+
* 4. 删除或者更新需要删除和更新的组合
2642+
*
2643+
* @param elements
2644+
*/
2645+
async createElementGroup(elements: IElement[], undoActionCallback: ElementActionCallback, redoActionCallback: ElementActionCallback): Promise<IElementGroup> {
2646+
if (elements.length < 1) return;
2647+
// 对给定的组件所属的链表节点进行重新排序
2648+
const sortedElements = this.sortElements(elements);
2649+
// 找到给定组件的层级最高的组件,我们将要把组合组件插入到这个组件之后
2650+
const targetElement = sortedElements[sortedElements.length - 1];
2651+
// 目标组件所属的组合
2652+
const targetElementGroup = targetElement.group;
2653+
// 目标组件所属的组合的祖先组件
2654+
const targetElementGroupAncestors = targetElementGroup?.ancestorGroups;
2655+
// 目标组件在目标组件所属的组合中的索引
2656+
let targetIndexOfGroupSubs = -1;
2657+
// 计算目标组件在目标组件所属的组合中的索引
2658+
targetIndexOfGroupSubs = targetElementGroup?.model.subIds.indexOf(targetElement.id);
2659+
// 计算移动组件位置时,受影响的组件
2660+
const { actionParams, removedGroups, updatedGroups, outerLayerIdSet, elementIdSet, removedGroupIdSet } = this._calcEffectedElementsOfMoved(
2661+
sortedElements,
2662+
targetElementGroup,
2663+
targetElementGroupAncestors,
2664+
);
2665+
// 顶层组合集合
2666+
const outerLayerElements: IElement[] = this.getOrderedElementsByIds(Array.from(outerLayerIdSet));
26322667
await undoActionCallback(actionParams);
26332668
// 创建组合组件
2634-
const group = new ElementGroup(this._createElementGroupObject(nonSubElements), this.shield);
2669+
const nGroup = new ElementGroup(this._createElementGroupObject(outerLayerElements), this.shield);
26352670
// 将前n-1个组件从链表中删除
2636-
const removeNodes = this._removeNodesByElements(elements.slice(0, elements.length - 1));
2671+
const removedNodes = this._removeNodesByElements(sortedElements.slice(0, sortedElements.length - 1));
26372672
// 将removeNodes移动到targetElement之前
2638-
removeNodes.forEach(node => {
2673+
removedNodes.forEach(node => {
26392674
// 插入到targetElement之前
26402675
this._elementList.insertBefore(node, targetElement.node, false);
26412676
// 这里只更新非子组件的groupId
2642-
if (nonSubIdSet.has(node.value.id)) {
2677+
if (outerLayerIdSet.has(node.value.id)) {
26432678
// 更新组件的groupId
2644-
this.updateElementModel(node.value.id, { groupId: group.id });
2679+
this.updateElementModel(node.value.id, { groupId: nGroup.id });
26452680
}
26462681
});
26472682
// 如果目标组合存在,则需要维护目标组合与新建组合的父子关系
26482683
if (targetElementGroup) {
26492684
// 原始的目标组合的子组件id集合
26502685
const subIds = [...targetElementGroup.model.subIds];
26512686
// 将目标组件id替换为新建组合的id
2652-
subIds.splice(targetIndexOfGroupSubs, 1, group.id);
2687+
subIds.splice(targetIndexOfGroupSubs, 1, nGroup.id);
26532688
// 更新目标组合的子组件id集合
26542689
this.updateElementModel(targetElementGroup.id, { subIds });
26552690
// 更新新建组合的groupId
2656-
group.model.groupId = targetElementGroup.id;
2691+
nGroup.model.groupId = targetElementGroup.id;
26572692
}
26582693
// 将新建组合插入到targetElement之后
2659-
this._insertNewGroup(group, targetElement);
2694+
this._insertNewGroup(nGroup, targetElement);
26602695
const groupAddedParams: ElementsActionParam = {
26612696
type: ElementActionTypes.Added,
2662-
data: [group],
2697+
data: [nGroup],
26632698
};
26642699
await undoActionCallback([groupAddedParams]);
26652700
// 组合添加之前的回调函数的参数
26662701
actionParams.push(groupAddedParams);
26672702
// 移除需要删除的组合
2668-
removedGroups.forEach(group => {
2669-
this.removeElement(group);
2703+
removedGroups.forEach(rGroup => {
2704+
this.removeElement(rGroup);
26702705
});
26712706
// 更新需要更新的组合
2672-
updatedGroups.forEach(group => {
2707+
updatedGroups.forEach(uGroup => {
26732708
// 计算组合的子组件id集合
2674-
const subIds = group.model.subIds.filter(id => !elementIds.includes(id) && !removedGroupIdSet.has(id));
2709+
const subIds = uGroup.model.subIds.filter(id => !elementIdSet.has(id) && !removedGroupIdSet.has(id));
26752710
// 更新组合的子组件id集合
2676-
this.updateElementModel(group.id, { subIds });
2711+
this.updateElementModel(uGroup.id, { subIds });
26772712
// 因为组合内的子组件发生变化,需要刷新组合的尺寸和位置
2678-
(group as IElementGroup).refreshBySubs();
2679-
group.refreshOriginals();
2713+
(uGroup as IElementGroup).refreshBySubs();
2714+
uGroup.refreshOriginals();
26802715
});
26812716
await redoActionCallback(actionParams);
26822717
}
@@ -3332,12 +3367,67 @@ export default class StageStore implements IStageStore {
33323367

33333368
/**
33343369
* 将组件移动到指定位置
3335-
*
3336-
* @param ids
3337-
* @param target
3338-
* @param dropType
3370+
*
3371+
* @param ids
3372+
* @param target
3373+
* @param dropType
3374+
* @param undoActionCallback
3375+
* @param redoActionCallback
3376+
* @returns
33393377
*/
3340-
async moveElementsTo(ids: string[], target: string, dropType: TreeNodeDropType): Promise<void> {
3341-
3378+
async moveElementsTo(ids: string[], target: string, dropType: TreeNodeDropType, undoActionCallback: ElementActionCallback, redoActionCallback: ElementActionCallback): Promise<void> {
3379+
if (ids.length === 0 || !target) return;
3380+
const elements = this.getOrderedElementsByIds(ids);
3381+
let targetElement = this.getElementById(target);
3382+
// 获取所有要移动的组件的组合id集合
3383+
const groupIds: Set<string> = new Set();
3384+
elements.forEach(element => {
3385+
if (element.model.type === CreatorTypes.group) {
3386+
groupIds.add(element.id);
3387+
}
3388+
});
3389+
// 目标组合的id
3390+
let targetGroupId: string | undefined = undefined;
3391+
// 目标组合
3392+
let targetGroup: IElementGroup | undefined = undefined;
3393+
// 目标组合的子组件id集合
3394+
let targetSubIds: string[] = [];
3395+
// 目标组件在目标组合中的索引
3396+
let targetIndexOfGroupSubs = -1;
3397+
// 插入到组合内部的操作
3398+
if (dropType === TreeNodeDropType.inner && targetElement.isGroup) {
3399+
targetGroupId = targetElement.id;
3400+
targetSubIds = targetElement.model.subIds;
3401+
targetElement = this._elementsMap.get(targetSubIds[targetSubIds.length - 1]);
3402+
} else if (targetElement.isGroupSubject) {
3403+
targetGroupId = targetElement.model.groupId;
3404+
targetSubIds = this._elementsMap.get(targetGroupId)?.model.subIds || [];
3405+
targetIndexOfGroupSubs = targetSubIds.indexOf(targetElement.id);
3406+
targetGroup = targetElement.group;
3407+
}
3408+
const actionParams: ElementsActionParam[] = [];
3409+
const updatedGroupIdSet: Set<string> = new Set();
3410+
const removedGroupIdSet: Set<string> = new Set();
3411+
elements.forEach(element => {});
3412+
let newSubIds: string[] = [];
3413+
if (targetGroupId) {
3414+
actionParams.push({
3415+
type: ElementActionTypes.GroupUpdated,
3416+
data: [this.getElementById(targetGroupId)],
3417+
});
3418+
targetGroup = this.getElementById(targetGroupId) as IElementGroup;
3419+
}
3420+
await undoActionCallback(actionParams);
3421+
if (targetGroup) {
3422+
if (targetIndexOfGroupSubs > -1) {
3423+
targetSubIds.splice(targetIndexOfGroupSubs + 1, 0, ...newSubIds);
3424+
} else {
3425+
targetSubIds.push(...newSubIds);
3426+
}
3427+
this.updateElementModel(targetGroupId, { subIds: targetSubIds });
3428+
targetGroup.refreshBySubs();
3429+
targetGroup.refreshOriginals();
3430+
}
3431+
await redoActionCallback(actionParams);
33423432
}
33433433
}

src/types/IElement.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1442,4 +1442,9 @@ export type ElementTreeNode = Partial<
14421442
};
14431443

14441444
// 组件树节点拖动类型
1445-
export type TreeNodeDropType = "before" | "after" | "inner" | "none";
1445+
export enum TreeNodeDropType {
1446+
before = "before",
1447+
after = "after",
1448+
inner = "inner",
1449+
none = "none",
1450+
}

0 commit comments

Comments
 (0)