Gutenberg 导航遮罩关闭块(core/navigation-overlay-close)全解析:属性、编辑器 UI 与服务端渲染实现
【免费下载链接】gutenbergThe Block Editor project for WordPress and beyond. Plugin is available from the official repository.项目地址: https://gitcode.com/GitHub_Trending/gu/gutenberg
core/navigation-overlay-close是 Gutenberg(WordPress 块编辑器)中用于关闭导航遮罩(Navigation Overlay)的专用按钮块,它解决了移动端/小屏导航菜单展开后“如何一键收起”这一交互问题。本文以 packages/block-library/src/navigation-overlay-close/README.md 为骨架,结合该块的block.json、编辑器端edit.jsx、服务端index.php与样式源码,逐层拆解它的元数据声明、属性与 Supports 配置、编辑器界面、服务端渲染逻辑以及“仅在导航遮罩模板部件内可插入”的约束机制,帮助你彻底理解并能够自定义这一动态块。
块概览:一个动态渲染的“关闭按钮”
从 README 中可以看到该块的核心元信息:
- 名称(Name):
core/navigation-overlay-close - 分类(Category):
design(设计) - API 版本(API Version):
3 - 块类型(Block Type):Dynamic(动态块,由服务端渲染,不在文章内容中保存 HTML)
- 关键词(Keywords):
close、overlay、navigation、menu
这些声明定义在 block.json 中("$schema": "https://schemas.wp.org/trunk/block.json"),服务端通过register_block_type_from_metadata()读取该文件完成注册,前端注册则由 index.js 中的init()调用initBlock()完成。
“Dynamic / 服务端渲染”意味着它属于动态块:文章内容里只保存块注释,不保存最终 HTML。块标记(Block Markup)为:
<!-- wp:navigation-overlay-close /-->最终渲染出的<button>按钮由服务端在请求时生成。这也是为什么关闭按钮上的文案“Close”能随站点语言自动翻译的原因之一——服务端渲染的默认文本走的是 WordPress 的 i18n 机制。
属性(Attributes)详解:displayMode 与 text
README 中给出了该块的两个属性,完整定义位于 block.json:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
displayMode | string | "icon" | 枚举(Enum):icon、text、both |
text | string | — | 自定义关闭按钮文案 |
displayMode:决定按钮呈现形式。icon只显示关闭图标(×),text只显示文字,both同时显示图标与文字。type声明为string并通过enum做取值校验,在 block 编辑器中,这一约束会阻止属性被设为枚举之外的值。text:关闭按钮的自定义文案。默认值为空,为空时服务端与编辑器都会回退到翻译后的Close。
属性在编辑器与服务端是如何被消费的
编辑器端(edit.jsx)中:
const { displayMode, text } = attributes; const showIcon = displayMode === 'icon' || displayMode === 'both'; const showText = displayMode === 'text' || displayMode === 'both'; // Use translated default if text is empty const displayText = text || __( 'Close' );服务端(index.php)中同样处理:
$text = empty( $attributes['text'] ) ? __( 'Close' ) : $attributes['text']; $display_mode = empty( $attributes['displayMode'] ) ? 'icon' : $attributes['displayMode']; $show_icon = 'both' === $display_mode || 'icon' === $display_mode; $show_text = 'both' === $display_mode || 'text' === $display_mode;可以看到编辑器与服务端对属性的解释完全一致,保证了“所见即所得”:编辑器中预览的图标/文字组合与前端渲染结果一一对应。
Supports 支持项:颜色、间距与排版控制
README 罗列了该块的supports声明,完整定义(含实验性默认控件)在 block.json:
- color
gradients:false(不提供渐变背景)__experimentalDefaultControls.background:true(默认显示背景色控件)__experimentalDefaultControls.text:true(默认显示文字颜色控件)
- spacing
padding:true(支持内边距)__experimentalDefaultControls.padding:true
- typography
fontSize:true、lineHeight:true- 实验性支持:
__experimentalFontFamily、__experimentalFontWeight、__experimentalFontStyle、__experimentalTextTransform、__experimentalTextDecoration、__experimentalLetterSpacing __experimentalDefaultControls.fontSize:true
注意:README 中的 Supports 表是自动生成文档的“稳定”子集,而
block.json中还包含一批__experimental前缀的排版/默认控件声明(字体族、字重、字风格、文字变换、文字装饰、字间距)。这些以__experimental开头的支持项属于实验性 API,可能在后续版本调整,实际能力以当前仓库 block.json 为准。
这些 Supports 让用户无需写 CSS 就能在侧边栏中调整按钮的背景色、文字颜色、内边距与排版(字号、行高、字重等),并且通过__experimentalDefaultControls让最常用的控件在面板默认展开。由于 style.scss 中按钮显式继承了颜色与字体(见下文“样式”一节),主题的theme.json与全局样式设置能够以块级优先级覆盖这些继承值。
编辑器端实现:Settings 面板与内联编辑
edit.jsx 是该块的编辑器界面实现,核心逻辑分为两块:
1. 检查器侧边栏:Display Mode(显示模式)切换
通过InspectorControls包裹一个ToolsPanel,其中放置ToggleGroupControl供用户在Icon / Text / Both三种模式间切换(edit.jsx):
<ToolsPanel label={ __( 'Settings' ) } resetAll={ () => setAttributes( { displayMode: 'icon' } ) } dropdownMenuProps={ dropdownMenuProps } > <ToolsPanelItem label={ __( 'Display Mode' ) } isShownByDefault hasValue={ () => displayMode !== 'icon' } onDeselect={ () => setAttributes( { displayMode: 'icon' } ) } > <ToggleGroupControl label={ __( 'Display Mode' ) } value={ displayMode } onChange={ ( value ) => setAttributes( { displayMode: value } ) } isBlock > <ToggleGroupControlOption value="icon" label={ __( 'Icon' ) } /> <ToggleGroupControlOption value="text" label={ __( 'Text' ) } /> <ToggleGroupControlOption value="both" label={ __( 'Both' ) } /> </ToggleGroupControl> </ToolsPanelItem> </ToolsPanel>注意resetAll与onDeselect都把displayMode重置为icon——这与block.json中的默认值"icon"保持一致。
2. 画布内编辑:图标与富文本
画布中的<button>预览根据showIcon/showText渲染图标(来自@wordpress/icons的close图标)与文本;文本部分使用RichText实现内联编辑(edit.jsx):
<button { ...blockProps } type="button" aria-label={ ! showText ? __( 'Close' ) : undefined }> { showIcon && <Icon icon={ close } /> } { showText && ( <RichText identifier="text" value={ displayText } onChange={ ( value ) => setAttributes( { text: value } ) } tagName="span" className="wp-block-navigation-overlay-close__text" allowedFormats={ [ 'core/bold', 'core/italic' ] } /> ) } </button>几个值得注意的实现细节:
RichText的tagName为span、className为wp-block-navigation-overlay-close__text,与服务端渲染输出的 span 类名完全对齐(见下文),确保编辑态与前台样式一致。allowedFormats限定为core/bold与core/italic,即文案只允许加粗和斜体,避免富文本污染按钮语义。- 当纯图标模式(
showText为 false)时,按钮通过aria-label="Close"提供无障碍替代文本;服务端渲染在相同条件下也会输出aria-label(详见下一节)。
服务端渲染实现:render_block_core_navigation_overlay_close
作为动态块,该块没有save输出 HTML,而是由 index.php 中的render_block_core_navigation_overlay_close()回调完成渲染(文档注释标记@since 7.0.0,即该块自 Gutenberg 7.0 起引入):
function render_block_core_navigation_overlay_close( $attributes ) { $text = empty( $attributes['text'] ) ? __( 'Close' ) : $attributes['text']; $display_mode = empty( $attributes['displayMode'] ) ? 'icon' : $attributes['displayMode']; $show_icon = 'both' === $display_mode || 'icon' === $display_mode; $show_text = 'both' === $display_mode || 'text' === $display_mode; $button_text = ''; if ( $show_icon ) { $button_text .= '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" aria-hidden="true" focusable="false"><path d="M13 11.8l6.1-6.3-1.1-1-6.1 6.2-6.1-6.2-1.1 1 6.1 6.3-6.5 6.7 1.1 1 6.5-6.6 6.5 6.6 1.1-1z" /></svg>'; } if ( $show_text ) { $button_text .= '<span class="wp-block-navigation-overlay-close__text">' . wp_kses_post( $text ) . '</span>'; } $wrapper_attributes = get_block_wrapper_attributes(); $html_content = sprintf( '<button %1$s type="button" %2$s >%3$s</button>', $wrapper_attributes, ! $show_text ? 'aria-label="' . __( 'Close' ) . '"' : '', $button_text ); return $html_content; }渲染逻辑可以归纳为四点:
- 默认值回退:
text为空时回退到翻译后的Close;displayMode为空时按icon处理。 - 图标内联输出:图标不是外部图片引用,而是直接内联输出 24×24 的 SVG(
aria-hidden="true" focusable="false",对辅助技术隐藏),路径数据与编辑器图标(见 icon.jsx)同源,均为“×”闭合形状。 - 文本安全输出:文案经
wp_kses_post过滤后包裹在wp-block-navigation-overlay-close__textspan 中,与编辑器端RichText的类名一致。 - 无障碍属性:纯图标/图文模式下,只要没有显示文本就输出
aria-label="Close"(type="button"固定防止表单提交语义)。
块注册通过register_block_type_from_metadata( __DIR__ . '/navigation-overlay-close', ... )绑定render_callback,并挂载到init钩子(index.php)。
插入限制机制:只能放在导航遮罩模板部件里
该块不能随意插入任意位置,index.js 通过blockEditor.__unstableCanInsertBlockType过滤器限制其插入范围:
addFilter( 'blockEditor.__unstableCanInsertBlockType', 'core/navigation-overlay-close/restrict-to-overlay-template-parts', ( canInsert, blockType ) => { if ( blockType.name !== 'core/navigation-overlay-close' ) { return canInsert; } if ( ! canInsert ) { return canInsert; } return isWithinNavigationOverlay(); } );- 只有目标块是
core/navigation-overlay-close时才拦截; - 原有
canInsert已是 false 则直接放行; - 否则调用
isWithinNavigationOverlay()判断当前编辑上下文是否位于“导航遮罩模板部件”内。
isWithinNavigationOverlay()定义于 packages/block-library/src/utils/is-within-overlay.js:它通过字符串访问core/editorstore(避免 block-library 包对@wordpress/editor产生硬依赖),在postType === 'wp_template_part'时取实体记录并判断area === NAVIGATION_OVERLAY_TEMPLATE_PART_AREA。该常量的值为'navigation-overlay',定义于 navigation/constants.js。
也就是说:普通文章/页面编辑器里看不到这个块,只有编辑导航遮罩模板部件(area 为navigation-overlay)时才能插入,从机制上保证了该按钮始终服务于遮罩场景。
样式实现:继承与按钮重置
style.scss 定义了按钮外观,关键点有二:
- 继承父级排版:由于
<button>的用户代理样式会破坏font/color继承,样式用:where()选择器显式继承颜色与全部排版属性(style.scss)。:where()零特异性写法让theme.json和全局样式的块级值仍然能够获胜。 - 按钮基础重置:
inline-flex布局、gap: 0.5em、去边框去背景、cursor: pointer,并对内联 SVG 固定 24×24、fill: currentColor;焦点态提供outline-offset: 2px保证键盘可达性(style.scss)。样式通过block.json中的"style": "wp-block-navigation-overlay-close"在前后台按需加载。
与导航遮罩块的协作:在 navigation/index.php 中的实际应用
该块的最终用途体现在 navigation/index.php 的遮罩渲染流程中:
- 导航块通过
overlay属性选中某个模板部件作为自定义遮罩,渲染时会检查遮罩 HTML 中是否包含关闭按钮(block_core_navigation_overlay_html_has_close_block,见 navigation/index.php); - 若遮罩中存在关闭按钮且导航是交互式的,则用
WP_HTML_Tag_Processor为关闭按钮添加 Interactivity API 指令(block_core_navigation_add_directives_to_overlay_close),实现点击后收起遮罩的交互行为(navigation/index.php); - 同时会递归禁用遮罩内嵌套导航块的遮罩菜单,防止“遮罩套遮罩”的嵌套问题(
disable_overlay_menu_for_nested_navigation_blocks,见 navigation/index.php)。
因此,一个典型的用法是:在“导航遮罩模板部件”中放置该关闭按钮,再让导航块的overlay属性指向该模板部件,从而获得完全自定义的移动端菜单展开/收起体验。
小结
core/navigation-overlay-close是一个小而精的动态块:它用两个属性(displayMode、text)控制图标/文字组合,用一套完整且可扩展的supports声明接入颜色、间距与排版控制;编辑器端通过ToolsPanel+ToggleGroupControl+RichText提供直观的编辑体验;服务端渲染负责输出带无障碍属性的内联 SVG 按钮;插入范围则被严格限制在导航遮罩模板部件内,并与导航块的 Interactivity API 指令协同工作。阅读本文时,可将 README.md 作为快速参考,将 block.json、index.php、edit.jsx 与 style.scss 作为深入研读的实现入口,它们共同构成了该块从元数据到渲染输出的完整链路。
【免费下载链接】gutenbergThe Block Editor project for WordPress and beyond. Plugin is available from the official repository.项目地址: https://gitcode.com/GitHub_Trending/gu/gutenberg
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考