From 5af9f6e27a472de599a7aa99191f3d3c610803d4 Mon Sep 17 00:00:00 2001 From: roymondchen Date: Sat, 9 May 2026 16:38:10 +0800 Subject: [PATCH] =?UTF-8?q?feat(editor):=20=E6=96=B0=E5=A2=9E=20canDropIn?= =?UTF-8?q?=20=E9=85=8D=E7=BD=AE=E7=BB=9F=E4=B8=80=E6=8E=A7=E5=88=B6=20lay?= =?UTF-8?q?er/stage=20=E6=8B=96=E6=8B=BD=E6=94=BE=E5=85=A5=E8=A1=8C?= =?UTF-8?q?=E4=B8=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 支持通过 scene 区分图层树、画布拖动、组件库新增三种场景; 返回 false 阻止放入,返回 Id 可重定向放入目标节点。 layer 场景下若禁用某节点的 inner,其子节点的 before/after 也会被同步禁用以避免被绕过。 Co-authored-by: Cursor --- docs/api/editor/props.md | 81 +++++++++++++++++++ packages/editor/src/Editor.vue | 6 ++ packages/editor/src/editorProps.ts | 11 +++ packages/editor/src/hooks/use-stage.ts | 1 + .../editor/src/layouts/sidebar/Sidebar.vue | 4 + .../src/layouts/sidebar/layer/LayerPanel.vue | 9 ++- .../src/layouts/sidebar/layer/use-drag.ts | 68 ++++++++++++++-- .../src/layouts/workspace/viewer/Stage.vue | 26 +++++- packages/editor/src/type.ts | 37 +++++++++ packages/stage/src/ActionManager.ts | 30 +++++-- packages/stage/src/StageCore.ts | 1 + packages/stage/src/types.ts | 19 +++++ 12 files changed, 277 insertions(+), 16 deletions(-) diff --git a/docs/api/editor/props.md b/docs/api/editor/props.md index 4d205ed4..c9f10b11 100644 --- a/docs/api/editor/props.md +++ b/docs/api/editor/props.md @@ -793,6 +793,87 @@ const isContainer = (el) => ``` +## canDropIn + +- **详情:** + + 用于自定义判断当前正在拖动的源是否可以拖入目标节点内部。同时覆盖"组件树拖动"和"画布拖入"两类场景,通过第三个参数 `scene` 区分;返回值有 3 种语义。 + + **scene 取值:** + + | scene | 触发场景 | `sourceIds` | `targetId` | + | --- | --- | --- | --- | + | `'layer'` | "已选组件"面板组件树拖动 | 被拖动节点 id(单选时长度为 1) | 目标节点 id | + | `'stage-drag'` | 画布上拖动已有组件 | 被拖动组件 id 列表(多选时为多个) | 候选容器节点 id | + | `'stage-add'` | 从左侧组件列表拖入新组件到画布 | 始终为空数组(尚无 id,可仅依据 `targetId` 判断) | 候选容器节点 id | + + **返回值语义:** + + | 返回值 | layer | stage-drag | stage-add | + | --- | --- | --- | --- | + | `false` | 禁用 inner;同时禁用所有"target 子节点的 before/after"(这些位置等价于放入 target,避免被绕过) | 阻止该容器被高亮命中 | 取消此次拖入 | + | `Id`(string \| number) | 将 inner 拖入目标重定向为该 id 对应的节点;与 `false` 一致禁用所有"target 子节点的 before/after" | 高亮命中切换到该 id 对应元素,最终拖入到该节点 | 直接将组件添加到该 id 对应节点(layout 坐标也基于其 DOM 重新计算) | + | `true` / `void` / `undefined` | 按原 targetId 正常拖入 | 同左 | 同左 | + + `scene` 取 `'stage-drag'` 或 `'stage-add'` 时该函数会被透传给 `StageCore` 的 `canDropIn`,因此直接使用 `@tmagic/stage` 时同样生效 + + :::tip + - 可通过 `editorService.getNodeById(id, false)` 把 id 还原为 `MNode` 以便基于业务字段(`type`、`name` 等)做判断。 + - 该函数为**同步**调用(拖动事件在浏览器中需要立即响应,不接受异步返回)。 + - 重定向到一个不存在或非容器的目标 id 时会被忽略:layer/stage-add 场景会取消此次拖入;stage-drag 场景不会高亮。 + ::: + +- **默认值:** `undefined` + +- **类型:** `(sourceIds: Id[], targetId: Id, scene: 'layer' | 'stage-drag' | 'stage-add') => Id | boolean | void` + +- **示例 1:禁止某些组件拖入特定容器** + +```html + + + +``` + +- **示例 2:将拖入"卡片外壳"重定向到"卡片内容"内层容器** + +```html + + + +``` + ## containerHighlightClassName - **详情:** diff --git a/packages/editor/src/Editor.vue b/packages/editor/src/Editor.vue index 642914cb..62e11e44 100644 --- a/packages/editor/src/Editor.vue +++ b/packages/editor/src/Editor.vue @@ -27,6 +27,7 @@ :indent="treeIndent" :next-level-indent-increment="treeNextLevelIndentIncrement" :layer-node-is-expandable="layerNodeIsExpandable" + :can-drop-in="canDropIn" >