Gutenberg 核心块深度解析:Spacer(core/spacer)间距占位块的属性、渲染与源码实现
【免费下载链接】gutenbergThe Block Editor project for WordPress and beyond. Plugin is available from the official repository.项目地址: https://gitcode.com/GitHub_Trending/gu/gutenberg
Spacer 是 Gutenberg(WordPress 块编辑器)内置的“间距占位”核心块,用于在块之间插入空白并自定义其高度(在横向 Flex 布局中还可自定义宽度)。本文以 Spacer 块文档 为骨架,结合 block.json、edit.jsx、save.jsx 等仓库源码,完整讲解其块元数据、属性、支持能力、前后端渲染标记、编辑器拖拽交互与历史迁移机制,帮助开发者理解该类静态占位块的设计模式并正确使用、扩展或二次开发。
一、块总览:名称、分类、API 版本与块类型
根据 Spacer 块文档 与 block.json 中的元数据,该块的基本身份信息如下:
- Name(块名):
core/spacer - Title(标题):
Spacer - Category(分类):
design(设计类块,与分隔线 Separator、按钮 Button 等同属一类) - API Version(块 API 版本):
3(即apiVersion: 3,声明于 block.json 第 3 行) - Block Type(块类型):Static(静态块),其标记直接保存在文章内容(post content)中,而非由服务端渲染生成
从源码结构看,core/spacer的注册入口位于 index.js,它导出metadata(来自block.json)、name,以及包含icon、transforms、edit、save、deprecated的settings对象;块图标使用@wordpress/icons中的resizeCornerNE(右上角拖拽调整图标),直观传达了“可拖拽调整大小”的核心交互语义。整个块目录还包含 constants.js、controls.jsx、deprecated.jsx、editor.scss、style.scss 等文件,共同构成完整的前端实现。
二、属性(Attributes)解析
Spacer 的属性通过 block.json 中的attributes属性声明,共两个:
| Attribute(属性) | Type(类型) | Default(默认值) | Description(说明) |
|---|---|---|---|
height | string | "100px" | 垂直方向占位高度,默认 100px |
width | string | — | 水平方向占位宽度(用于 Flex 横向布局场景),无默认值 |
2.1 为何是字符串而非数字
值得注意:height与width的类型是string(如"100px"),而不是数字。这是因为 Spacer 支持任意 CSS 长度单位(px、em、rem、vw、vh),字符串形态可以携带单位信息。这一点在 deprecated.jsx 的迁移逻辑中体现得尤为明显:旧版本(API 早期)这两个属性曾是number类型(默认100),迁移函数会把数字统一转换为带px的字符串:
migrate( attributes ) { const { height, width } = attributes; return { ...attributes, width: width !== undefined ? `${ width }px` : undefined, height: height !== undefined ? `${ height }px` : undefined, }; }从源码结构可以推断,这一从number到string的演变,为后续支持间距预设变量(spacing preset CSS 变量)与多单位输入扫清了障碍——getSpacingPresetCssVar、isValueSpacingPreset等工具函数处理的都是字符串形态的值。
2.2 间距预设值的支持
在 controls.jsx 中,DimensionInput组件通过useSpacingSizes()获取主题定义的间距尺寸预设;当预设数量大于等于 2 时,侧栏使用SpacingSizesControl以预设档位(Preset)的形式供用户选择,选中的值形如var:preset|spacing|50;当预设不足 2 个(主题禁用了自定义间距尺寸)时,则退化为UnitControl直接输入数值。而 save.jsx 在保存时统一调用getSpacingPresetCssVar(),将预设字符串解析为对应的 CSS 变量(var(--wp--preset--spacing--50))后再写入内联样式,从而保证主题预设能被正确应用。
三、支持的块能力(Supports)
block.json 中声明的supports决定了编辑器为 Spacer 提供哪些通用能力,文档整理如下:
anchor(锚点):true— 允许为 Spacer 设置 HTML 锚点(id),便于页面内定位与自定义 JS 挂接。spacing.margin:["top","bottom"]— 支持设置上下外边距。值得注意的是该能力还带有实验性默认控件配置:"__experimentalDefaultControls": { "margin": true }即编辑器侧栏默认展示 margin 控件,无需用户展开“更多设置”。
interactivity.clientNavigation:true— 声明该块支持客户端导航(Client Side Navigation,即区块间的无刷新路由切换),在站点编辑器交互式导航(Interactivity API)场景下保持兼容。
从源码层面看,supports中声明的能力由 Gutenberg 的 block-supports 机制统一处理;Spacer 对应的支持处理器可在仓库的 lib/block-supports 目录中找到(如anchor.php、spacing.php等),这些 PHP 端处理器会在服务端渲染时依据块属性为最终 HTML 补充类名与内联样式。该目录下的settings.php则负责把这些支持能力的配置汇聚成编辑器可读的元数据。
四、上下文(Context)
Spacer 是块上下文(Block Context)的使用者而非提供者:它在 block.json 中通过usesContext: ["orientation"]声明消费父块提供的orientation上下文,用于判断自身处于纵向(vertical)还是横向(horizontal)布局容器中。
在 edit.jsx 中,const { orientation } = context取出该值;同时还会读取父级布局信息__unstableParentLayout,综合判断后得到inheritedOrientation:
- 若父容器是 Flex 布局(
type === 'flex'或默认类型为 flex),且父级未显式声明方向,则默认按horizontal处理; - 否则继承父级的
orientation(典型场景是组块 Group 的纵向 Flex 布局)。
这一上下文机制让同一个 Spacer 块能智能地决定:在普通块流(垂直方向)中拖拽“高度”,在 Flex 横向容器中拖拽“宽度”,无需用户手动切换模式。
五、块标记(Block Markup)与前端的静态渲染
Spacer 属于静态块,保存到文章内容中的标记由 save.jsx 生成。文档给出的标准标记示例如下:
<!-- wp:spacer {"height":"100px"} --> <div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div> <!-- /wp:spacer -->5.1 渲染要点
结合 save.jsx 源码,可以看到保存函数的关键逻辑:
const finalHeight = selfStretch === 'fill' || selfStretch === 'fit' ? undefined : height; return ( <div { ...useBlockProps.save( { style: { height: getSpacingPresetCssVar( finalHeight ), width: getSpacingPresetCssVar( width ), }, 'aria-hidden': true, } ) } /> );aria-hidden="true":Spacer 对屏幕阅读器等辅助技术不可见,它只是视觉占位,不应被朗读或聚焦;class="wp-block-spacer":前端样式入口,由 style.scss 定义,其中仅有一条规则clear: both;,用于清除浮动干扰、保证占位在文档流中的稳定性;- 内联样式承载尺寸:
height、width直接以内联 style 输出(支持间距预设 CSS 变量); - Flex 场景的例外:当内联
style.layout.selfStretch为fill或fit时,不再输出默认height,把尺寸交给 Flex 拉伸行为决定。
useBlockProps.save()会把块元数据中声明的锚点、类名等能力合并进最终的<div>,因此示例标记中即使没有显式写出 class,渲染后也会带上wp-block-spacer。
六、编辑器交互:拖拽调整、工具栏与侧栏控件
Spacer 在编辑器中最重要的体验是直接拖拽调整大小。这一能力由 edit.jsx 中的ResizableSpacer组件实现,它基于@wordpress/components的ResizableBox封装。
6.1 拖拽方向与最小尺寸
- 纵向(垂直)场景:只允许向下拖拽,
enable配置为{ bottom: true },其余方向全部false; - 横向(Flex 场景):只允许向右拖拽,
enable配置为{ right: true }; - 最小尺寸:
MIN_SPACER_SIZE定义于 constants.js,值为0,即理论上可拖拽到 0,但编辑器样式层做了兜底(见下文 6.4)。
拖拽过程中通过onResize把临时尺寸写入 state(temporaryHeight/temporaryWidth),仅当onResizeStop时才正式setAttributes持久化;同时用toggleSelection(false/true)在拖拽期间临时禁用文本选择,避免干扰。
6.2 侧栏控件(InspectorControls)
controls.jsx 通过InspectorControls在右侧设置面板提供Height(高度)与Width(宽度)输入控件,二者按orientation条件渲染:
orientation === 'horizontal'时显示 Width;- 否则显示 Height;
- 控件包裹在
ToolsPanel中,可通过下拉菜单展开/收起,resetAll会把属性重置为{ width: undefined, height: '100px' }。
DimensionInput内部有两个值得注意的细节:
- 单位限制:可用单位取自主题设置
spacing.units,并过滤掉%(百分比)——注释明确说明在多数上下文里百分比相对父容器没有确定意义;默认单位为['px', 'em', 'rem', 'vw', 'vh'],且各单位的默认提示值分别为px: 100, em: 10, rem: 10, vw: 10, vh: 25; - 拖拽时强制 px:
computedValue在isResizing为 true 时强制使用px单位拼接,避免拖拽过程中单位跳动。
6.3 拖拽手柄与悬停提示
ResizableBox配置了__experimentalShowTooltip与__experimentalTooltipProps,在拖拽时于角落位置显示实时尺寸气泡;showHandle={ isSelected }意味着只有选中块时才显示拖拽手柄。
6.4 编辑器样式兜底
editor.scss 为编辑器内的 Spacer 提供了两类关键样式:
- 在块元素上叠加一层
::before不可见点击区域(宽度 100%、高度 100%,最小 10px),保证即使 Spacer 被拖到 1px 高/宽,用户依然有足够大的目标可以选中它; - 选中/悬停时给调整容器渲染半透明背景(浅色主题
rgba(0,0,0,0.1),深色主题rgba(255,255,255,0.15)),直观呈现占位区域范围;custom-sizes-disabled类配合“禁用自定义间距尺寸”设置(disableCustomSpacingSizes,读取自 edit.jsx 中的editorSettings.disableCustomSpacingSizes)提供视觉反馈。
七、Flex 布局容器内的行为
这是 Spacer 相对复杂的能力:当它位于 Flex 容器(如 Group 的横向排列)中时,通过style.layout.selfStretch与style.layout.flexSize控制自身拉伸行为。edit.jsx 中的useEffect维护了一套状态同步逻辑:
- 进入 Flex 容器且未设置拉伸:自动把当前高度/宽度迁移到
flexSize并设selfStretch: 'fixed',原height/width清零; selfStretch为fill或fit:清除对应的height/width,让 Spacer 跟随 Flex 拉伸;- 离开 Flex 容器:把
flexSize回写到height/width,并清除layout中的 Flex 相关字段。
这些变更统一通过__unstableMarkNextChangeAsNotPersistent()标记为“不写入历史记录”,以useEffect内的注释说明——这是为了不干扰撤销/重做(undo/redo)栈。此外,编辑态样式还做了两个关键处理:纵向 Flex 容器中给 Spacer 设置minWidth: 48,避免其在垂直排列中被压缩到零宽而无法选中;拖拽时移除flex-grow、设置flex-basis为临时尺寸,保证尺寸反馈即时准确。
八、与其他块的转换(Transforms)
transforms.js 定义了 Spacer 的单向块转换:可转换为core/separator(分隔线)块,转换时仅保留锚点属性:
const transforms = { to: [ { type: 'block', blocks: [ 'core/separator' ], transform: ( { anchor } ) => { return createBlock( 'core/separator', { anchor: anchor || undefined, } ); }, }, ], };在块工具栏的“转换为”菜单中,用户可将一个 Spacer 一键变更为分隔线(反之不可)。从源码结构看,该文件位于块目录内并由 index.js 注入settings.transforms。
九、历史兼容与数据迁移(Deprecations)
deprecated.jsx 记录了块的历史版本,用于兼容旧内容:
- 旧版属性为
number类型(height默认100、width无默认值),保存的 HTML 直接把数字作为内联样式; - 新版属性为
string类型,因此提供了migrate函数,在解析旧文章时把数字自动补上px单位迁移为新结构,并注册对应的旧版save函数用于识别旧标记。
这正是前面 2.1 提到的“数字 → 字符串”演变在兼容层的落地,也是 Gutenberg 核心块常见的向前兼容模式:新代码读旧数据时先迁移再渲染,保证历史文章不破版。
十、前端样式与主题定制
Spacer 的前端样式非常克制——style.scss 仅有:
.wp-block-spacer { clear: both; }尺寸完全由内联样式驱动。这意味着:
- 主题无需为 Spacer 编写额外 CSS 即可正常工作;
- 开发者可通过设置主题的
spacing.units与间距预设(spacing preset)来控制侧栏可选的单位与档位; - 在块支持层,
spacing.margin支持意味着主题可以通过样式系统(如lib/theme.json、lib/global-styles-and-settings.php)为 Spacer 的上下外边距提供默认值或预设。
若需要查看块级支持的完整清单与源码入口,可继续阅读 block.json 与 lib/block-supports 目录下的处理器实现。
十一、源码地图与延伸阅读
Spacer 块完整源码目录为 packages/block-library/src/spacer,关键文件职责如下:
| 文件 | 职责 |
|---|---|
| block.json | 块元数据:名称、属性、支持能力、上下文声明 |
| index.js | 注册入口,组装 settings(icon/transforms/edit/save/deprecated) |
| edit.jsx | 编辑器编辑组件:拖拽调整、Flex 适配、状态同步 |
| save.jsx | 静态标记输出:内联样式 +aria-hidden |
| controls.jsx | 侧栏设置面板:Height/Width 输入、单位过滤、预设支持 |
| transforms.js | 转换为core/separator |
| deprecated.jsx | 旧版(number 属性)数据迁移与兼容渲染 |
| style.scss | 前端样式(clear: both) |
| editor.scss | 编辑器样式:可选中兜底区域、选中高亮 |
通过本文的梳理可以看到,Spacer 虽然是一个“最小”的核心块,却完整覆盖了 Gutenberg 块开发的典型要素:JSON 元数据声明、静态渲染、上下文消费、拖拽交互、Flex 适配、块转换与历史迁移。对于想要深入理解块编辑器静态块开发模式的读者,这份源码是一份简洁且完备的参考范本。
【免费下载链接】gutenbergThe Block Editor project for WordPress and beyond. Plugin is available from the official repository.项目地址: https://gitcode.com/GitHub_Trending/gu/gutenberg
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考