GrapesJS 如何用 block:custom 事件渲染自定义 Block 面板?
【免费下载链接】grapesjsFree and Open source Web Builder Framework. Next generation tool for building templates without coding项目地址: https://gitcode.com/GitHub_Trending/gr/grapesjs
在 GrapesJS 编辑器里,默认的 Block Manager 是一个内置 Drag & Drop 的轻量 UI。文档的说法是:简单的场景够用,但"adding more complex elements requires a replace of the default UI"——需要更复杂的 Block 面板时,就要换掉默认 UI。官方给出的路径只有一条:在blockManager配置里声明custom: true,然后订阅block:custom事件,把面板的渲染和更新逻辑全部接管过来。本文基于 GrapesJS 仓库中的 Blocks 模块指南、Block Manager API 和 Block 参考 给出完整操作路径,指南注明该内容适用于 GrapesJS v0.17.27 或更高版本。
完成后你会得到:默认 block 列表不再渲染,你在事件提供的container元素里渲染自己的面板,并且面板里的 block 仍然可以拖入画布。
准备条件
- 一个已经
grapesjs.init()完成初始化的编辑器实例。 - 保留 Blocks 面板:事件 payload 中的
container是在 Blocks 面板命令运行时才被设置的(见 OpenBlocks 命令实现)。文档中的 Vue 示例也展示了把自定义面板挂到默认容器的做法,文档原话是"that is up to your preferences"——放在哪里由你决定,但container本身来自面板命令。 - 了解 Block 的基本属性:
label、content、media、category等,见 Block 参考。
第一步:声明 custom: true
const editor = grapesjs.init({ container: '#gjs', // ...其他配置 blockManager: { custom: true, }, });custom是 blockManager 配置 中的一个布尔项,默认值为false,官方注释写明它的作用是"Avoid rendering the default block manager UI"。也就是说:一旦开启,编辑器自己不再画默认 block 列表,你的 UI 必须自己渲染,否则面板会是空的。这一步没有可运行的命令,判断标准就是打开 Blocks 面板后看不到默认列表。
第二步:订阅 block:custom 并渲染面板
指南给出的核心写法:
editor.on('block:custom', (props) => { // props.blocks (Array<Block>) - Array of all blocks // props.dragStart (Function<Block>) - 触发 block 拖拽开始 // props.dragStop (Function<Block>) - 触发 block 拖拽结束 // props.container (HTMLElement) - 你可以把 UI 追加进去的默认元素 // 这里写你自己的渲染/更新逻辑 });事件触发时携带的完整数据在源码类型BlocksCustomData中声明为:bm(BlockManager 模块)、blocks、container、dragStart(block, ev?)、drag(ev)、dragStop(cancel?),见 类型定义。指南列出的四个主要字段之外,拖拽进行中的drag回调和bm引用可以从这里确认。
一个说明性示例(文档本身未给出 vanilla 完整示例,以下按上述字段拼出最小渲染逻辑,具体事件绑定方式可自行替换):
editor.on('block:custom', ({ blocks, container, dragStart, drag, dragStop }) => { // container 类型为 HTMLElement | undefined,事件可能先于面板打开触发 if (!container) return; container.innerHTML = ''; blocks.forEach((block) => { const el = document.createElement('div'); el.textContent = block.get('label'); el.addEventListener('mousedown', (ev) => dragStart(block, ev)); el.addEventListener('mousemove', drag); el.addEventListener('mouseup', () => dragStop()); container.appendChild(el); }); });三个拖拽回调对应拖动的开始、进行中、结束三个阶段;示例把 mousedown / mousemove / mouseup 分别绑定到三个阶段,这是文档未约束的一种可行接法。
事件何时触发
block:custom不是一次性的,它的触发点有三处,理解这几点能避免"回调没执行"或"面板没更新"两类疑问:
- 编辑器初始渲染完成后,BlockManager 的
postRender会触发一次该事件,见 实现代码。此时面板命令还没跑过,payload 里的container可能为空,所以上面示例里做了空值判断。 - Blocks 面板命令运行时,如果
custom: true,会把面板容器写入 payload 的container并再次触发事件,见 OpenBlocks 命令。 - Block 集合发生变化时事件会重新触发——指南原话是
block:custom"will give you all the information on any requested change",源码中对所有 block 事件做了 debounce 监听再触发。这意味着你在自定义面板里增删 block 后,可以拿到最新的blocks数组重绘 UI,而不需要自己维护一份列表。
如何验证
- 打开 Blocks 面板:默认 block 列表不再出现(
custom: true已避免渲染默认 UI),面板容器内显示的是你在回调里追加的 DOM。 - 在回调中打印
props.blocks(例如各 block 的 id),与初始化时blocks配置的定义核对一致;随后用editor.Blocks.add('BLOCK-ID', {...})或editor.Blocks.remove('BLOCK-ID')编程式增删 block(方法用法见 Blocks API),回调应再次触发且列表随之变化。 - 验证拖拽:在自定义面板上拖动某个 block 到画布,拖动开始/结束分别走到
dragStart/dragStop,成功放下后画布中会出现该 block 的content对应的 Component。可以用 事件文档 中的block:drag:stop事件(回调参数为 dropped Component 与 Block)来确认落下是否成功。
限制与注意
- 自定义 UI 只接管渲染,block 定义本身的规则不变:不要把函数等不可序列化属性放进 block,也不要把 styles 写进 block——指南明确指出这样保存后函数会丢失、样式无法被编辑器安全清理,这些都应留在 component 里。
- Blocks API 的增删改主要更新 Block Manager UI,与画布中已存在的 Components 无关,这一点在指南中有专门警告。
- 如果只想做 UI 状态同步而不替换整个面板,也可以直接监听文档列出的其他事件(
block:add、block:remove、block:update、block:drag:start等),完整列表见 Block Manager API 的 Available Events。
【免费下载链接】grapesjsFree and Open source Web Builder Framework. Next generation tool for building templates without coding项目地址: https://gitcode.com/GitHub_Trending/gr/grapesjs
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考