拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Open Pencil 的 LayerTreeRoot:构建无样式可定制图层树面板的 SDK 组件指南

Open Pencil 的 LayerTreeRoot:构建无样式可定制图层树面板的 SDK 组件指南 前端桌面应用AI 应用MCP 服务【免费下载链接】open-pencilAI-native design editor. Open-source Figma alternative.项目地址https://gitcode.com/gh_mirrors/op/open-pencil点击查看免费下载LayerTreeRoot是 Open Pencil开源的 AI 原生设计编辑器Vue SDKopen-pencil/vue中面向图层树layer tree的无样式headless结构原语。它把图层树的树形结构、选择状态、展开/折叠分支、可见性/锁定切换、重命名与拖拽排序等交互逻辑全部封装在内而把 DOM 标记markup与样式styling完全交给应用自身。本文将以 LayerTreeRoot 官方文档 为主线结合 源码实现 与配套 API讲解它的职责边界、上下文模型、生命周期同步机制并给出可直接复制的实战用法。1. 组件定位结构由 SDK 管外观由应用管LayerTreeRoot的设计目标可以概括为一句话提供可复用的树结构与交互接线而不内置任何表现层without built-in presentation。它不像传统组件库那样输出一套固定的带样式 UI而是通过作用域插槽scoped slot暴露数据与动作由你在插槽内自由组装行内容、缩进样式、选中高亮与拖拽指示器。这意味着在实际使用中你需要用LayerTreeRoot包住整个面板区域让 SDK 负责从编辑器场景图scene graph构建树模型、维护展开状态、计算可见行、处理选择与拖拽在插槽内用自有组件例如你自己的TreeView渲染items并通过插槽暴露的select、toggleExpand等动作把点击事件接回 SDK每一行既可以使用配套的LayerTreeItem它提供选择、展开、可见性、锁定、直接重命名等行级状态与动作也可以完全自写行组件仅从useLayerTree()取所需上下文。2. 核心概念树模型、可见行与选择状态要正确使用LayerTreeRoot先理解它向下游暴露的三个核心概念。它们都定义在 context.ts 中概念类型含义itemsRefLayerNode[]当前页面下的图层树根级节点数组LayerNode含id、name、type、layoutMode、visible、locked与嵌套的childrenvisibleRowsComputedRefLayerRow[]按当前展开状态拍平后的可见行列表每行含node、level层级从 1 起与hasChildrenselectedIdsComputedRefSetstring当前编辑器中选中的节点 id 集合与画布选区保持同步树模型的构建buildLayerTreeModel树模型由 model.ts 中的buildLayerTreeModel(graph, parentId)从场景图构建它从当前页开始深度优先遍历parent.childIds跳过internalOnly的内部节点把每个SceneNode映射为轻量LayerNode并同时返回byId索引用于后续的补丁式更新patch。visibleLayerRows(items, expandedIds)则把树按展开集合拍平成带level的行序列某行有子节点且其 id 在展开集合中才会继续展开下一层。也就是说展开状态完全由expanded数组驱动LayerTreeRoot会替你维护这个数组并保证删除节点后残留的展开 id 会被自动过滤见下文的 rebuild 逻辑。选择模式layerSelectionForTarget选择逻辑集中在layerSelectionForTarget根据目标 id、锚点 idselectionAnchorId与LayerSelectionModeadditive、range两个布尔位计算新选区非 range单击additivefalse直接替换选区additive 则在当前选区上增/删目标range结合锚点与目标在可见行中的索引取二者之间的连续区间配合 additive 可把区间并入现有选区。这正是实现按住 Ctrl/Shift 多选、框选连选等交互的底层依据Open Pencil 编辑器的选择行为与画布是一致的。3. 插槽协议组件暴露的数据与动作LayerTreeRoot的模板基于 reka-ui 的TreeRoot构建并通过单个默认插槽把全部能力下放见 LayerTreeRoot.vue。插槽参数完整列表如下插槽参数说明items树根级LayerNode[]flattenItemsreka-ui 计算出的拍平节点列表visibleRows按展开状态拍平的LayerRow[]含 level/hasChildrenexpanded当前展开的 id 数组treeVersion树版本号每次重建模型 1可用来强制行组件刷新selectedIdsSetstring当前选区focused面板是否获得焦点用于键盘导航与视觉聚焦态draggingId正在拖拽的行 id无拖拽时为 nullinstruction拖拽放置指令reorder-above/reorder-below/make-childinstructionTargetId拖拽指令对应的目标行 idactions动作集合select(id, mode)、toggleExpand(id)、setFocused(bool)、setVirtualizer(v)下面是根据 导航面板指南 给出的最小可运行示例——SDK 管理结构应用管理标记与样式LayerTreeRoot v-slot{ items, selectedIds, select, toggleExpand, getKey, getChildren } TreeView :itemsitems :selected-idsselectedIds :get-keygetKey :get-childrengetChildren selectselect toggle-expandtoggleExpand / /LayerTreeRoot注示例中的getKey/getChildren由内部TreeRoot提供分别返回节点 id 与子节点数组如果你完全自写行渲染可改用visibleRows 插槽内的actions.select/actions.toggleExpand。4. 行级渲染LayerTreeItem 与 useLayerTreeLayerTreeRoot官方文档特别指出可以搭配LayerTreeItem使用也可以用自己的插槽渲染行。LayerTreeItem是默认的行组件其默认插槽会收到以下行级状态与动作见 LayerTreeItem.vue状态node、level、hasChildren、isSelected、isDragging、instruction、instructionTargetId、focused、padLeft按(level-1) * indentPerLevel计算的左缩进值动作actions.select(additive)、actions.toggleExpand()、actions.toggleVisibility()、actions.toggleLock()、actions.rename(name)。行级动作会先emit到LayerTreeRoot供外部监听再落到编辑器toggleVisibility调用editor.toggleNodeVisibility(id)、toggleLock调用editor.toggleNodeLock(id)、rename调用editor.renameNode(id, name)因此这些操作默认就是带撤销undo语义的编辑器动作。如果你在自写行组件中只想读取上下文而无需外层插槽可以使用配套的组合式函数import { useLayerTree } from open-pencil/vue // 在 LayerTreeRoot 的任何后代组件中 const ctx useLayerTree() console.log(ctx.visibleRows.value) // 当前可见行 ctx.select(nodeId, { additive: true, range: false }) ctx.toggleExpand(nodeId)useLayerTree()通过注入键LAYER_TREE_KEYSymbol(layer-tree)返回最近的LayerTreeRoot上下文如果在LayerTreeRoot之外调用会直接抛出错误提示这能帮助你在开发期尽早发现结构错误见 context.ts。上下文完整字段LayerTreeContext除了上述状态外还包含供内部协作的成员editor当前编辑器实例、treeVersion、setupDrag、setVirtualizer、setRowRef等。多数情况下你只需关注插槽参数与select/toggleExpand/toggleVisibility/toggleLock/rename这套动作。所有公开类型LayerNode、LayerRow、LayerSelectionMode、LayerDragInstruction、LayerTreeContext、LayerTreeVirtualizer均从 index.ts 导出。5. 与编辑器生命周期的同步机制LayerTreeRoot不是一次性渲染的静态树而是与编辑器场景图保持实时同步的“活”结构。从 LayerTreeRoot.vue 可以看到它订阅了一系列编辑器事件事件处理策略graph:replaced/page:changed立即重建整棵树rebuildTreenode:created/node:deleted/node:reparented/node:reordered合并到微任务队列中调度一次重建scheduleTreeRebuild避免高频操作反复重建node:updated只做补丁更新patchTreeNode仅当改动涉及name、type、layoutMode、visible、locked时才就地同步对应行否则忽略selection:changed自动展开选中节点的祖先分支expandSelectionAncestors必要时滚动到选中行两个细节值得注意增量更新而非全量重建普通属性变化走patchLayerNode原地更新LayerNode只有结构变化增删/换父/重排才触发整树重建这是它在大文档中保持流畅的关键设计选区联动当选区变化时组件会自动把选中节点的祖先 id 加入expanded确保“选中即展开可见”这与主流设计工具的行为一致。组件在onScopeDispose中统一退订所有事件避免内存泄漏。6. 拖拽重排与换容器useLayerDragLayerTreeRoot内部内置了基于atlaskit/pragmatic-drag-and-drop的拖拽能力useLayerDrag见 useLayerDrag.ts支持三种放置指令reorder-above把源行插入目标行之前reorder-below把源行插入目标行之后make-child把源行放入目标容器末尾成为子节点。实现要点每行通过setupItem注册为可拖拽源draggable与放置目标dropTargetForElements并结合命中框计算attachInstruction与缩进量indentPerLevel推导指令容器行editor.graph.isContainer允许被放入子节点block 列表不含make-child普通叶子节点则禁止放置校验包含source.id ! data.id不能放到自己身上与isDescendant(targetId, sourceId)不能放进自己的后代里放置成功后调用editor.reorderChildWithUndo(sourceId, parentId, index)执行带撤销的重排make-child场景还会把目标容器自动展开保证移动后节点立即可见。拖拽过程中的draggingId、instruction、instructionTargetId会随插槽参数实时下发因此你可以据此绘制“插入线/放入高亮”等视觉反馈——这也是为什么组件本身不内置样式、但交互体验却能完全自定义的原因。7. 在真实面板中的位置与配套 API在 Open Pencil 中图层树是左侧导航面板的核心区域。官方 导航面板指南 推荐的布局是上方为页面列表PageListRoot下方为图层树LayerTreeRoot行组件内部承载属性详情与直接重命名。与之配套的 API 还包括LayerTreeItem单行组件提供选择、展开、可见性、锁定与重命名useLayerTree在任意后代组件中获取最近LayerTreeRoot的上下文useLayerDrag拖拽重排/换容器状态与动作的组合式函数useSelectionState与选择状态相关的组合式 APIPageListRoot页面列表根组件。这些组件同属open-pencil/vue的无样式组件体系均可在 组件索引 中查阅。8. 完整实战组装一个自定义图层树面板综合以上内容一个典型的“自带标记与样式”的面板可以这样组织script setup langts import { LayerTreeRoot } from open-pencil/vue /script template LayerTreeRoot :indent-per-level20 v-slot{ items, visibleRows, expanded, selectedIds, toggleExpand, actions } !-- 行渲染完全自定义样式由应用决定 -- ul classlayer-panel template v-forrow in visibleRows :keyrow.node.id li :class{ selected: selectedIds.has(row.node.id), dragging: row.node.id $attrs.draggingId } :style{ paddingLeft: (row.level - 1) * 20 px } clickactions.select(row.node.id, false) dblclickrow.hasChildren actions.toggleExpand(row.node.id) {{ row.node.name }} /li /template /ul /LayerTreeRoot /template要点回顾visibleRows已经替你算好每个节点的level与hasChildren无需自己递归缩进可以用indentPerLevel属性默认 16统一控制也可以在行内自行计算actions中的动作直接作用于编辑器操作自动进入撤销栈如需更细粒度的行级能力可见性/锁定/重命名/拖拽改用LayerTreeItem或直接调用useLayerTree()。9. 总结LayerTreeRoot是 Open Pencil Vue SDK 中“结构即服务、样式归应用”理念的典型代表它把图层树的模型构建、展开状态、可见行计算、选区同步、事件订阅与拖拽重排全部封装并通过插槽与useLayerTree()把状态和动作完整暴露给应用层。掌握它之后你可以在不触碰渲染细节的前提下快速搭建出与 Open Pencil 编辑器深度联动、交互行为一致的自定义图层树面板。进一步可阅读 LayerTreeItem、useLayerTree 与 useLayerDrag 继续深入。赞分享前端桌面应用AI 应用MCP 服务【免费下载链接】open-pencilAI-native design editor. Open-source Figma alternative.项目地址https://gitcode.com/gh_mirrors/op/open-pencil点击查看免费下载相关推荐open-pencil LayerTreeItem 组件详解基于 open-pencil/vue 的无头图层树行原语open pencil LayerTreeItem 组件详解基于 open pencil/vue 的无头图层树行原语 LayerTreeItem 是 ope前端桌面应用AI 应用MCP 服务open-pencil SDK LayerTreeItem 详解面向应用定制的头less图层树行原语open pencil SDK LayerTreeItem 详解面向应用定制的头less图层树行原语 LayerTreeItem 是 open pencil前端桌面应用AI 应用MCP 服务open-pencil open-pencil/vue 无头组件体系用无样式原语构建自定义设计编辑器界面open pencil open pencil/vue 无头组件体系用无样式原语构建自定义设计编辑器界面 本篇基于 open pencil 仓库中 pack前端桌面应用AI 应用MCP 服务上一篇重构AI编程范式Cline如何颠覆IDE开发体验下一篇Apache Hamilton UI完全指南可视化、监控和调试数据流水线的终极工具创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表