
GrapesJS Panels 面板模块 API 完全指南用 panelManager 打造自定义编辑器工具栏【免费下载链接】grapesjsFree and Open source Web Builder Framework. Next generation tool for building templates without coding项目地址: https://gitcode.com/GitHub_Trending/gr/grapesjsGrapesJS 的 Panels 模块负责管理编辑器界面中的面板Panel与按钮Button构成了顶部工具栏、侧边栏等所有 UI 控件的骨架。本文基于官方 API 文档 docs/api/panels.md结合仓库源码panels/index.ts、panels/config/config.ts 等系统讲解如何通过配置对象和editor.Panels模块 API 动态增删面板与按钮、绑定命令并控制其行为读完即可在真实项目中定制属于自己的编辑器工具栏。模块总览Panels 在 GrapesJS 中的角色在 GrapesJS 中面板Panel是承载按钮Button的容器按钮则是触发命令Command的入口。整个编辑器的交互入口几乎都由该模块驱动顶部工具栏Top Bar由commands与options面板组成右侧视图切换区域由views面板承载 Style Manager、图层、块等面板的开关按钮。从源码看该模块由PanelManager类实现它继承自Module基类内部维护一个Panels集合panels/index.ts对应的渲染由PanelsView完成。使用面板模块有两种途径初始化配置在grapesjs.init()时通过panels选项定义模块的初始状态如默认面板、按钮运行时 API编辑器实例化后通过editor.Panels获取模块实例调用其方法动态操作面板与按钮。const editor grapesjs.init({ panels: { // options } }); // 编辑器实例化后获取模块 const panelManager editor.Panels;初始化配置panels 配置对象在编辑器初始化阶段传入panels配置对象即可自定义模块的初始状态。配置类型定义于 panels/config/config.ts共两个顶层选项配置项类型默认值说明stylePrefixstringpn-面板/按钮的 CSS 类名前缀defaultsPanelProps[]见下方说明默认面板集合其中defaults数组中的每个面板对象可包含id、buttons按钮对象数组、以及 Panel.ts 中定义的其余属性content、visible、attributes、appendTo、resizable等。从源码 config.ts 可以看到内置的默认面板结构这正是标准 GrapesJS 界面顶部工具栏的由来commands面板预留给自定义命令按钮的占位面板options面板包含显示组件轮廓core:component-outline预览preview全屏fullscreen查看代码export-template四个按钮views面板包含 Style Manager、设置Traits、图层管理、块管理四个视图切换按钮。因此一个常见的自定义方式是覆盖defaults只保留你需要的按钮const editor grapesjs.init({ panels: { defaults: [ { id: options, buttons: [ { id: preview, className: fa fa-eye, command: preview, attributes: { title: 预览 }, }, ], }, ], }, });面板与按钮的数据模型在动手调用 API 之前理解底层数据模型有助于写出正确的配置。面板模型PanelPanel.ts的默认属性为属性默认值说明id面板唯一标识content面板内 HTML 内容visibletrue面板是否可见buttons[]按钮集合内部被包装为Buttons集合attributes{}渲染到面板 DOM 上的属性appendTo无指定 CSS 选择器将面板追加到该元素下resizable无boolean或ResizerOptions启用面板尺寸调整按钮模型ButtonButton.ts的默认属性为属性默认值说明id按钮唯一标识label按钮显示文本tagNamespan按钮渲染的 HTML 标签className额外 CSS 类command绑定的命令字符串/对象/函数context互斥上下文同 context 的按钮互斥激活attributes{}渲染到按钮 DOM 上的属性常用于title提示activefalse按钮激活状态togglabletrue是否可切换激活状态runDefaultCommandtrue激活时是否同时运行默认命令stopDefaultCommandfalse取消激活时是否同时停止默认命令disablefalse禁用按钮点击无响应dragDropfalse是否可拖拽options{}传给命令的附加选项核心 API 详解模块实例panelManager editor.Panels提供 8 个公开方法覆盖面板与按钮的增、删、查三个维度。以下逐一讲解示例均来自官方文档并可复制运行。获取面板集合与 DOMgetPanels / getPanelsEl// 返回面板集合Panels Collection const panels panelManager.getPanels(); // 返回面板容器的 HTMLElement const panelsEl panelManager.getPanelsEl();getPanels()返回的是内部Panels集合实例panels/index.ts基于 Backbone Collection可用each、where等集合方法遍历。getPanelsEl()返回PanelsView渲染出的根元素panels/index.ts它带有pn-panels类名方便你通过 DOM 操作定制外层布局。添加面板addPanelconst newPanel panelManager.addPanel({ id: myNewPanel, visible: true, buttons: [...], });addPanel接受一个属性对象或Panel实例返回添加后的Panelpanels/index.ts。从 Panel.ts 的实现可以看到传入的buttons数组会在构造时被自动包装为Buttons集合因此你可以放心地以普通对象数组的形式传入按钮。一个带完整功能的示例const panel panelManager.addPanel({ id: myToolbar, visible: true, content: div classmy-toolbar-label自定义工具栏/div, buttons: [ { id: btn-1, className: fa fa-star, command: someCommand, attributes: { title: 点我执行命令 }, }, ], // 可选让面板支持拖拽调整大小 resizable: true, });获取面板getPanelconst myPanel panelManager.getPanel(myPanel);getPanel(id)按 id 在集合中查找面板找到返回面板实例找不到返回nullpanels/index.ts。移除面板removePanel// 通过面板实例移除 const somePanel panelManager.getPanel(somePanel); const removedPanel panelManager.removePanel(somePanel); // 或直接传面板 id const removedPanel panelManager.removePanel(myNewPanel);removePanel接受面板实例或面板 id返回被移除的面板panels/index.ts。从 PanelsView.ts 的onRemove处理可以看到面板移除后其对应视图也会被同步销毁DOM 会自动清理。添加按钮addButtonconst newButton panelManager.addButton(myNewPanel, { id: myNewButton, className: someClass, command: someCommand, attributes: { title: Some title }, active: false, });addButton(panelId, button)向指定面板追加按钮面板不存在时返回nullpanels/index.ts。command属性是按钮的核心支持三种写法写法一字符串命令名推荐复用 Commands 模块中已注册的命令command: someCommand,写法二带run/stop方法的命令对象command: { run: function(editor) { // 按钮激活时执行 }, stop: function(editor) { // 按钮取消激活时执行 } },写法三函数等价于只有run的命令command: function(editor) { // 每次点击按钮时执行 }从按钮视图 ButtonView.ts 的updateActive实现可以看出三种写法的解析逻辑字符串会通过commands.get()查找已注册命令对象与函数会被包装为命令执行。同时激活按钮时若该命令没有stop方法command.noStop按钮会自动取消激活。移除按钮removeButtonconst removedButton panelManager.addButton(myNewPanel, { id: myNewButton, className: someClass, command: someCommand, attributes: { title: Some title }, active: false, }); const removedButton panelManager.removeButton(myNewPanel, myNewButton);removeButton(panelId, buttonId)从指定面板移除按钮返回被移除的按钮面板不存在时返回nullpanels/index.ts。获取按钮getButtonconst button panelManager.getButton(myPanel, myButton);getButton(panelId, id)在指定面板内按按钮 id 查找返回按钮实例或nullpanels/index.ts。按钮的激活、互斥与禁用机制掌握按钮的状态机是定制工具栏的关键这些行为定义在 ButtonView.ts 中激活切换点击按钮触发clicked→toggleActive通过model.active !active切换状态。若按钮处于激活态且togglable: false点击不会取消激活ButtonView.ts这正是views面板中 Style Manager 等按钮只开不关的原因。同组互斥Buttons.deactivateAll会根据context字段把同 context 的其他按钮置为非激活Buttons.ts。因此给同一组模式按钮设置相同的context即可实现单选互斥例如默认options面板中预览与组件轮廓按钮都通过context实现互斥。禁用disable: true的按钮在点击时直接忽略ButtonView.ts且视图层会添加禁用样式类。源码中还提供了disableAllButtons/disableAllButtonsExceptOne等集合级方法Buttons.ts适合按上下文批量控制按钮可用性。命令联动当listen开启且命令为字符串时按钮会监听run:${command}与stop:${command}事件使按钮激活状态与命令执行状态自动同步ButtonView.ts。面板渲染与自定义位置el 与 appendTo默认情况下所有面板都会被渲染进同一个pn-panels根容器中。但部分场景下你希望把面板放到页面其他位置此时可利用PanelProperties中的两个属性PanelsView.tsappendTo传入 CSS 选择器字符串面板会被追加到document.querySelector(appendTo)命中的元素中el直接传入已有的 DOM 元素引用面板视图将复用它不再生成新容器。panelManager.addPanel({ id: floatingPanel, appendTo: #my-custom-container, // 渲染到页面指定容器 buttons: [{ id: b1, command: someCommand }], });从 PanelView.ts 的render方法可见面板最终渲染结构包含按钮集合视图与content内容并带有pn-panel前缀的类名与ppfxeditor stylePrefix衍生样式类便于主题定制。完整示例为编辑器添加自定义导出工具栏综合以上内容下面是一个可运行的完整示例——为编辑器新增一个数据操作面板包含两个按钮一个通过字符串命令名触发已注册命令一个通过函数直接执行逻辑const editor grapesjs.init({ container: #gjs, // 先注册一个命令供按钮引用 commands: { add: { exportData() { const data editor.getProjectData(); console.log(项目数据, data); }, }, }, panels: { // 保留默认面板同时新增自定义面板 defaults: [ ...(grapesjs.plugins.get(grapesjs-preset-webpage) ? [] : []), // 说明此处可改为从编辑器默认配置继承或直接使用默认配置再追加 ], }, }); const panelManager editor.Panels; // 方案 A完全自定义一个新面板 panelManager.addPanel({ id: data-panel, visible: true, buttons: [ { id: export-btn, label: 导出, command: exportData, // 字符串命令 attributes: { title: 导出项目数据 }, }, { id: greet-btn, label: 问候, // 函数命令点击即执行 command: (ed) { console.log(Hello from ${ed.getProjectName() || GrapesJS}); }, }, ], }); // 方案 B往已存在的默认面板中追加按钮 panelManager.addButton(options, { id: my-toggle, className: fa fa-magic, command: { run(ed) { console.log(开始); }, stop(ed) { console.log(结束); }, }, togglable: true, context: myGroup, // 与同 context 按钮互斥 }); // 运行时读取 const panel panelManager.getPanel(data-panel); const btn panelManager.getButton(options, my-toggle); console.log(panel, btn);若默认面板被自定义defaults覆盖需要注意commands/options/views这些内置面板 id 的可用性——源码中的默认面板结构config.ts是理解这一行为的最佳参照。相关测试与进一步探索仓库为面板模块提供了完整的测试覆盖可作深入参考模块级 API 测试packages/core/test/specs/panels/index.ts端到端交互测试packages/core/test/specs/panels/e2e/PanelsE2e.js类型定义与导出packages/core/src/index.ts需要更深一层定制时可继续阅读 panels/view/ButtonView.ts 了解按钮点击与命令解析的完整链路或参考 docs/modules/Commands.md 掌握命令的注册与执行机制从而让面板按钮与编辑器命令体系无缝协作。【免费下载链接】grapesjsFree and Open source Web Builder Framework. Next generation tool for building templates without coding项目地址: https://gitcode.com/GitHub_Trending/gr/grapesjs创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考