
GrapesJS Layer Manager 完全指南API、事件与自定义图层树实现【免费下载链接】grapesjsFree and Open source Web Builder Framework. Next generation tool for building templates without coding项目地址: https://gitcode.com/GitHub_Trending/gr/grapesjsLayer Manager图层管理器是 GrapesJS 中将组件Components以树形结构可视化展示的核心模块它与画布联动承担层级查看、排序、显隐切换、锁定、重命名等职责。本文以仓库中 docs/api/layer_manager.md 为主线结合 packages/core/src/navigator 下的源码实现与测试用例系统讲解 Layer Manager 的初始化配置、全部公开事件、12 个核心 API 方法及其底层原理并给出基于layer:custom事件从零实现自定义图层 UI 的完整方案。Layer Manager 是什么Layer Manager 负责将编辑器中的 Component即 Components 体系中的模型以可展开的树形结构渲染出来是 GrapesJS 默认 UI 中位于左侧面板的图层面板。它具备以下能力以树形结构展示组件层级父子关系、嵌套深度以缩进表示拖拽排序、重新组织组件结构切换组件显示/隐藏visibility展开/折叠open与锁定/解锁locked双击重命名组件点击选中组件并与画布双向联动悬停高亮、选中滚动定位从源码结构看该模块位于 packages/core/src/navigator核心类LayerManager继承自Module见 packages/core/src/navigator/index.ts视图层由ItemViewpackages/core/src/navigator/view/ItemView.ts与ItemsViewpackages/core/src/navigator/view/ItemsView.ts构成。初始化与获取模块实例你可以在编辑器初始化时通过layerManager配置项定制模块的初始状态const editor grapesjs.init({ // ... layerManager: { // ... }, })编辑器实例化完成后通过editor.Layers获取模块引用即可调用其全部 APIconst layers editor.Layers;配置项详解layerManager支持的全部配置项定义在 packages/core/src/navigator/config/config.ts默认值见同文件config()工厂函数config.ts#L111-L127配置项类型默认值说明stylePrefixstringCSS 类名前缀appendTostring | HTMLElement指定渲染容器query 字符串或 DOM 元素为空则不渲染默认 UIsortablebooleantrue全局开关是否允许拖拽排序图层hidablebooleantrue全局开关是否显示隐藏图层的眼睛图标hideTextnodebooleantrue是否隐藏文本节点textnode与br标签rootstring作为图层根的组件选择器query默认根为 wrapper根容器组件。若未指定或未找到对应元素则回退使用主 wrappershowWrapperbooleantrue是否在图层树中显示 wrapper 本身showHoverbooleantrue画布中悬停组件时是否在图层中联动scrollCanvasboolean | ScrollIntoViewOptions{ behavior: smooth, block: nearest }在图层中选中组件时是否滚动画布定位到该组件block: nearest可避免整页滚动问题scrollLayersboolean | ScrollIntoViewOptions{ behavior: auto, block: nearest }在画布中选中组件时是否滚动图层列表定位highlightHoverbooleantrue悬停图层项时是否高亮画布对应组件custombooleanfalse为true时不渲染默认图层管理器配合layer:custom事件使用自定义 UIonInitfunction() {}⚠️ 实验性图层项初始化时的回调可用于监听组件属性变化并触发重渲染onRenderfunction() {}⚠️ 实验性图层项渲染后的回调可操作图层 DOMextendobject{}扩展 Layer 视图对象即ItemView的方法或属性一个典型的初始化配置示例const editor grapesjs.init({ // ... layerManager: { // 若未指定 root 或元素未找到则使用主 wrapper 作为根 root: #my-custom-root, sortable: false, hidable: false, } });注意图层是组件的直接映射只有组件在编辑器中加载完成例如从远程端点加载项目数据后图层才会可用。从实现上看config中的hideTextnode直接影响图层项是否可入树LayerManager.__isLayerableindex.ts#L353-L359会排除 textnode、br以及layerable属性为假的组件sortable则在ItemsView构造时决定是否为该容器创建ComponentSorter实例ItemsView.ts#L41-L61排序行为通过LayersComponentNode树类与垂直嵌套拖拽策略DragDirection.Vertical、nested: true实现。可用事件Layer Manager 提供 4 个事件类型定义与回调签名见 packages/core/src/navigator/types.tslayer:root根图层发生变化时触发回调参数为新的根组件。editor.on(layer:root, (component) { ... });源码依据LayerManager.__onRootChangeindex.ts#L337-L343在model的root属性变化时调用em.trigger(events.root, root)。layer:component组件图层更新时触发如 open、status、locked、custom-name、components、classes 等属性变化回调参数为更新后的组件及可选选项。editor.on(layer:component, (component, opts) { ... });源码依据LayerManager.onLoad中监听了以component:update:*开头的多个属性事件index.ts#L54-L56、index.ts#L83统一调用updateLayerindex.ts#L370-L373触发该事件。layer:custom自定义图层事件。当配置custom: true时用于告知你把自定义 UI 挂载到默认容器中。回调参数为包含container与root的对象类型LayerCustomEventData见 types.ts#L48-L51。editor.on(layer:custom, ({ container, root }) { ... });源码依据LayerManager.__trgCustomindex.ts#L361-L368在根变化等场景被调用container即默认提供的容器元素。layer:render组件图层渲染完成时触发回调参数为包含component与渲染后图层 DOM 元素el的对象类型LayerRenderEventData见 types.ts#L53-L56。editor.on(layer:render, ({ component, el }) { ... });源码依据ItemView.__renderItemView.ts#L449-L455在每次渲染完成后触发LayerEvents.render与配置项onRender回调并行执行。方法 API 详解模块提供 12 个公开方法。以下逐一说明参数、返回值与底层实现对应 packages/core/src/navigator/index.ts 中同名方法。setRoot(component)将指定组件设置为图层根参数可为 Component 实例或选择器字符串返回设置后的根组件。const component editor.getSelected(); layers.setRoot(component);实现细节index.ts#L99-L111传入字符串时会在 wrapper 内执行wrapper.find(component)查找未找到则回退为 wrapper同时会通过__getLayerFromComponent支持组件delegate.layer代理映射。getRoot()获取当前根图层组件。const layerRoot layers.getRoot();实现细节index.ts#L119-L121直接读取模块模型中缓存的root值。getComponents(component)获取指定组件的合法子图层组件即排除不可入层的组件如 textnode 与layerable为假的组件。const component editor.getSelected(); const components layers.getComponents(component); console.log(components);返回ArrayComponent。实现细节index.ts#L132-L137先取全部子组件经__getLayerFromComponent映射再用__isLayerable过滤。setOpen(component, value) / isOpen(component)更新 / 读取组件的图层展开状态。value为布尔值isOpen返回布尔值。// 展开指定组件的图层 layers.setOpen(component, true); // 判断是否展开 layers.isOpen(component); // true | false实现细节index.ts#L144-L155展开状态以open属性存储在组件模型上ItemView.updateOpening根据该属性切换展开样式类ItemView.ts#L263-L276。此外当画布选中组件变化时componentChangedindex.ts#L288-L312会自动展开其所有祖先图层并支持scrollLayers滚动定位。setVisible(component, value) / isVisible(component)更新 / 读取组件的图层可见状态对应画布中该组件是否display: none。// 隐藏组件 layers.setVisible(component, false); // 判断是否可见 layers.isVisible(component); // true | false实现细节setVisibleindex.ts#L162-L183通过操作组件的style.display实现——隐藏时把原display值暂存到__prev-display属性并置为none恢复时还原原值同时触发component:toggled事件以同步 Style Manager。isVisibleindex.ts#L190-L192通过判断样式display是否以none开头来确定。该逻辑在测试 packages/core/test/specs/navigator/view/ItemView.ts 中有明确覆盖display: none时返回false空值与block均返回true。setLocked(component, value) / isLocked(component)更新 / 读取组件的图层锁定状态锁定后组件在画布中不可编辑。layers.setLocked(component, true); layers.isLocked(component); // true | false实现细节index.ts#L199-L210锁定状态以locked属性存储在组件模型上。setName(component, value) / getName(component)更新 / 读取组件的图层显示名称。setName将名称写入组件的custom-name属性getName返回组件当前图层名称。layers.setName(component, My Custom Name); layers.getName(component); // My Custom Name实现细节index.ts#L217-L228getName委托给component.getName()该命名机制会优先使用custom-name否则回退到标签名等默认规则。双击图层名称进入编辑后ItemView.handleEditEndItemView.ts#L233-L245最终也调用model.setName(name)写回。getLayerData(component)从组件读取完整的图层数据对象。const component editor.getSelected(); const layerData layers.getLayerData(component); console.log(layerData);返回对象结构对应LayerData接口types.ts#L4-L12interface LayerData { name: string; // 图层名称 open: boolean; // 是否展开 selected: boolean; // 是否被选中组件 status 为 selected hovered: boolean; // 是否被悬停组件 status 为 hovered visible: boolean; // 是否可见 locked: boolean; // 是否锁定 components: Component[]; // 合法的子图层组件列表 }实现细节index.ts#L239-L251selected与hovered由组件status属性推导components复用getComponents。该方法与配套的内部方法setLayerDataindex.ts#L253-L282非文档公开 API共同构成自定义 UI 的数据读写通道。自定义图层 UIcustom: true默认 UI 无法满足复杂需求时可通过custom: true关闭默认渲染并结合事件自行实现图层树。基本骨架如下完整交互式示例见 docs/modules/Layers.md 的 Customization 章节const editor grapesjs.init({ // ... layerManager: { custom: true, // ... }, }); // 用此事件将你的 UI 追加到 GrapesJS 提供的默认容器中。 // 如果你不依赖核心面板也可以跳过此事件把 UI 放到其他位置。 editor.on(layer:custom, (props) { // props.container (HTMLElement) - 默认的容器元素可将 UI 挂载进来 // props.root (Component) - 当前的根组件 }); // 根图层变化时触发用于更新 UI 的根节点 editor.on(layer:root, (root) { // 更新你的 UI 根 }); // 组件更新时触发用于精准刷新对应图层项 editor.on(layer:component, (component) { // 更新你的 UI 中对应的图层 });在自定义实现中推荐的数据流是用layers.getLayerData(component)读取每个组件的图层状态渲染节点用layers.setOpen / setVisible / setLayerData / setName将 UI 交互写回编辑器并监听layer:component事件按需刷新。可参考docs/modules/Layers.md中附带的 Vue 演示模板模板注释内含完整拖拽排序、双击重命名、显隐切换、选中/悬停联动的实现其中Layers.canMove/Components.canMove与source.move(target, { at: index })展示了如何实现拖拽重组。总结Layer Manager 是 GrapesJS 组件体系与 UI 之间的桥梁editor.Layers上的 12 个公开方法覆盖了图层树的读、写与查询layer:root / layer:component / layer:custom / layer:render四个事件支撑了默认 UI 与自定义 UI 的双向同步。理解LayerData结构、open / locked / custom-name / status等组件属性与样式display的联动关系是深入定制该模块的关键。若需更底层的视图行为可继续阅读 ItemView.ts 的事件绑定与模板渲染逻辑以及 config.ts 中每个配置项对视图行为的开关作用。【免费下载链接】grapesjsFree and Open source Web Builder Framework. Next generation tool for building templates without coding项目地址: https://gitcode.com/GitHub_Trending/gr/grapesjs创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考