diff --git a/packages/editor/src/components/TreeNode.vue b/packages/editor/src/components/TreeNode.vue index bd0fc401..88baeead 100644 --- a/packages/editor/src/components/TreeNode.vue +++ b/packages/editor/src/components/TreeNode.vue @@ -4,6 +4,8 @@ class="m-editor-tree-node" :draggable="draggable" :data-node-id="data.id" + :data-parent-id="parent?.id" + :data-parents-id="parentsId" :data-is-container="Array.isArray(data.items)" @dragstart="handleDragStart" @dragleave="handleDragLeave" @@ -40,6 +42,8 @@ v-for="item in data.items" :key="item.id" :data="item" + :parent="data" + :parentsId="[...parentsId, data.id]" :node-status-map="nodeStatusMap" :indent="indent + 11" > @@ -91,11 +95,14 @@ const treeEmit = inject('treeEmit'); const props = withDefaults( defineProps<{ data: TreeNodeData; + parent?: TreeNodeData; + parentsId?: Id[]; nodeStatusMap: Map; indent?: number; }>(), { indent: 0, + parentsId: () => [], }, ); diff --git a/packages/editor/src/layouts/sidebar/layer/use-drag.ts b/packages/editor/src/layouts/sidebar/layer/use-drag.ts index 6355fde2..0cc91066 100644 --- a/packages/editor/src/layouts/sidebar/layer/use-drag.ts +++ b/packages/editor/src/layouts/sidebar/layer/use-drag.ts @@ -10,6 +10,7 @@ const dragState: { dragOverNodeId: Id; dropType: NodeDropType | ''; container: HTMLElement | null; + nodeId?: Id; } = { dragOverNodeId: '', dropType: '', @@ -50,6 +51,7 @@ export const useDrag = (services: Services | undefined) => { if (!targetEl || targetEl !== event.currentTarget) return; event.dataTransfer.effectAllowed = 'move'; + dragState.nodeId = targetEl.dataset.nodeId; try { event.dataTransfer.setData( @@ -70,30 +72,52 @@ export const useDrag = (services: Services | undefined) => { const labelEl = targetEl.children[0]; if (!labelEl) return; + removeClassName(labelEl, 'drag-before', 'drag-after', 'drag-inner'); + const { top: targetTop, height: targetHeight } = labelEl.getBoundingClientRect(); const distance = event.clientY - targetTop; const isContainer = targetEl.dataset.isContainer === 'true'; + const targetNodeId = targetEl.dataset.nodeId; + const { nodeId } = dragState; + const parentsId = targetEl.dataset.parentsId?.split(','); + + if (!targetNodeId) { + return; + } + + // 如果是悬浮在拖动的节点上方,则不响应 + if (parentsId) { + let targetIdIndex = -1; + for (let i = 0, l = parentsId.length; i < l; i++) { + const id = parentsId[i]; + if (nodeId === id) { + targetIdIndex = i; + } + + if (parentsId.includes(`${nodeId}`) && i >= targetIdIndex) { + return; + } + } + } + if (distance < targetHeight / 3) { dragState.dropType = 'before'; addClassName(labelEl, globalThis.document, 'drag-before'); - removeClassName(labelEl, 'drag-after', 'drag-inner'); } else if (distance > (targetHeight * 2) / 3) { dragState.dropType = 'after'; addClassName(labelEl, globalThis.document, 'drag-after'); - removeClassName(labelEl, 'drag-before', 'drag-inner'); } else if (isContainer) { dragState.dropType = 'inner'; addClassName(labelEl, globalThis.document, 'drag-inner'); - removeClassName(labelEl, 'drag-before', 'drag-after'); } if (!dragState.dropType) { return; } - dragState.dragOverNodeId = targetEl.dataset.nodeId || ''; + dragState.dragOverNodeId = targetNodeId; dragState.container = event.currentTarget as HTMLElement; event.preventDefault(); diff --git a/packages/editor/src/services/editor.ts b/packages/editor/src/services/editor.ts index efa2a480..05fc26d0 100644 --- a/packages/editor/src/services/editor.ts +++ b/packages/editor/src/services/editor.ts @@ -899,9 +899,20 @@ class Editor extends BaseService { const newLayout = await this.getLayout(targetParent); - for (const config of configs) { + // eslint-disable-next-line no-restricted-syntax + forConfigs: for (const config of configs) { const { parent, node: curNode } = this.getNodeInfo(config.id, false); - if (!parent || !curNode) throw new Error('找不要删除的节点'); + if (!parent || !curNode) { + continue; + } + + const path = getNodePath(curNode.id, parent.items); + + for (const node of path) { + if (targetParent.id === node.id) { + continue forConfigs; + } + } const index = getNodeIndex(curNode.id, parent);