Gutenberg 核心块深度解析:Spacer(core/spacer)间距占位块的属性、渲染与源码实现
2026/9/17 3:22:31 网站建设 项目流程

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,以及包含icontransformseditsavedeprecatedsettings对象;块图标使用@wordpress/icons中的resizeCornerNE(右上角拖拽调整图标),直观传达了“可拖拽调整大小”的核心交互语义。整个块目录还包含 constants.js、controls.jsx、deprecated.jsx、editor.scss、style.scss 等文件,共同构成完整的前端实现。

二、属性(Attributes)解析

Spacer 的属性通过 block.json 中的attributes属性声明,共两个:

Attribute(属性)Type(类型)Default(默认值)Description(说明)
heightstring"100px"垂直方向占位高度,默认 100px
widthstring水平方向占位宽度(用于 Flex 横向布局场景),无默认值

2.1 为何是字符串而非数字

值得注意:heightwidth的类型是string(如"100px"),而不是数字。这是因为 Spacer 支持任意 CSS 长度单位(pxemremvwvh),字符串形态可以携带单位信息。这一点在 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, }; }

从源码结构可以推断,这一从numberstring的演变,为后续支持间距预设变量(spacing preset CSS 变量)与多单位输入扫清了障碍——getSpacingPresetCssVarisValueSpacingPreset等工具函数处理的都是字符串形态的值。

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.clientNavigationtrue— 声明该块支持客户端导航(Client Side Navigation,即区块间的无刷新路由切换),在站点编辑器交互式导航(Interactivity API)场景下保持兼容。

从源码层面看,supports中声明的能力由 Gutenberg 的 block-supports 机制统一处理;Spacer 对应的支持处理器可在仓库的 lib/block-supports 目录中找到(如anchor.phpspacing.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;,用于清除浮动干扰、保证占位在文档流中的稳定性;
  • 内联样式承载尺寸heightwidth直接以内联 style 输出(支持间距预设 CSS 变量);
  • Flex 场景的例外:当内联style.layout.selfStretchfillfit时,不再输出默认height,把尺寸交给 Flex 拉伸行为决定。

useBlockProps.save()会把块元数据中声明的锚点、类名等能力合并进最终的<div>,因此示例标记中即使没有显式写出 class,渲染后也会带上wp-block-spacer

六、编辑器交互:拖拽调整、工具栏与侧栏控件

Spacer 在编辑器中最重要的体验是直接拖拽调整大小。这一能力由 edit.jsx 中的ResizableSpacer组件实现,它基于@wordpress/componentsResizableBox封装。

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内部有两个值得注意的细节:

  1. 单位限制:可用单位取自主题设置spacing.units,并过滤掉%(百分比)——注释明确说明在多数上下文里百分比相对父容器没有确定意义;默认单位为['px', 'em', 'rem', 'vw', 'vh'],且各单位的默认提示值分别为px: 100, em: 10, rem: 10, vw: 10, vh: 25
  2. 拖拽时强制 pxcomputedValueisResizing为 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.selfStretchstyle.layout.flexSize控制自身拉伸行为。edit.jsx 中的useEffect维护了一套状态同步逻辑:

  • 进入 Flex 容器且未设置拉伸:自动把当前高度/宽度迁移到flexSize并设selfStretch: 'fixed',原height/width清零;
  • selfStretchfillfit:清除对应的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默认100width无默认值),保存的 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.jsonlib/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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询