news 2026/9/16 20:13:21

Gutenberg Formatting Toolbar API 开发指南:为富文本工具栏添加自定义格式按钮

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Gutenberg Formatting Toolbar API 开发指南:为富文本工具栏添加自定义格式按钮

Gutenberg Formatting Toolbar API 开发指南:为富文本工具栏添加自定义格式按钮

【免费下载链接】gutenbergThe Block Editor project for WordPress and beyond. Plugin is available from the official repository.项目地址: https://gitcode.com/GitHub_Trending/gu/gutenberg

Formatting Toolbar API(格式工具栏 API)是 Gutenberg 块编辑器为开发者提供的官方扩展机制,用于向富文本格式化工具栏添加自定义按钮,并让按钮对选中的文本应用一种"格式"(format)。本指南以 Gutenberg 仓库 docs/how-to-guides/format-api.md 为骨架,结合@wordpress/rich-text@wordpress/block-editor等包的源码实现,逐步讲解如何注册格式类型、渲染工具栏按钮、切换格式作用域,以及按块类型条件显示按钮,最终在插件中构建出与内置 Bold、Italic 同等体验的自定义格式能力。

什么是 Format API

Format API 让开发者可以为格式化工具栏添加自定义按钮,并使按钮将一种format应用到文本选区上。在 WordPress 的术语体系中,format是一个具有文本级语义的 HTML 标签,用来给一段选中的文本赋予特殊含义。例如本教程中挂载到格式工具栏的按钮,会把选中的文本用<samp>标签包裹起来。

内置的粗体(Bold)按钮就是格式化工具栏中标准按钮的典型代表。在 Gutenberg 源码中,粗体正是通过 Format API 实现的:packages/format-library/src/bold/index.tsx定义了core/bold格式,其tagNamestrongclassNamenull,并在edit渲染函数中通过RichTextToolbarButton组件输出按钮、通过RichTextShortcut绑定快捷键,最后调用toggleFormat切换格式:

// packages/format-library/src/bold/index.tsx(节选) export const bold = { name, title, tagName: 'strong', className: null, edit( { isActive, value, onChange, onFocus, isVisible = true } ) { function onToggle() { onChange( toggleFormat( value, { type: name, title } ) ); } // ... return ( <> <RichTextShortcut type="primary" character="b" onUse={ onToggle } /> <RichTextToolbarButton name="bold" icon={ formatBold } title={ title } onClick={ onClick } isActive={ isActive } shortcutType="primary" shortcutCharacter="b" /> </> ); }, };

也就是说,你的自定义按钮与编辑器内置的粗体、斜体等按钮走的是同一条注册管线,这正是本指南想让你掌握的核心能力。

开始之前

本指南假定你已经熟悉 WordPress 插件的基本概念,以及如何在插件中加载 JavaScript。可以参阅 插件手册 复习相关知识。

你需要准备:

  • WordPress 开发环境
  • 一个已激活、配置就绪的最小插件
  • 用于构建和入队 JavaScript 的工具链

本指南以src/index.js作为修改的 JavaScript 文件。完成每一步后,运行npm run build会生成build/index.js,该文件随后被加载到文章编辑器页面中。

提示:构建产物(build/index.js)需要通过插件的 PHP 文件使用wp_enqueue_script正确入队,并在注册脚本时声明@wordpress/rich-text@wordpress/block-editor等依赖(或依赖wp-rich-textwp-block-editor等 WordPress 全局脚本句柄),编辑器才能识别这些模块的导入。

Step 1:注册一个新的格式类型

第一步是注册新格式。创建src/index.js并写入以下内容:

import { registerFormatType } from '@wordpress/rich-text'; registerFormatType( 'my-custom-format/sample-output', { title: 'Sample output', tagName: 'samp', className: null, } );

注册背后的校验逻辑

registerFormatType@wordpress/rich-text包导出(见 packages/rich-text/src/index.ts),其实现位于 packages/rich-text/src/register-format-type.js。该函数在真正写入 store 之前会做一系列校验,理解这些规则可以帮你避开常见的注册失败陷阱:

  • 名称必须是字符串,否则报错Format names must be strings.
  • 名称必须包含命名空间前缀,格式为[a-z][a-z0-9-]*\/[a-z][a-z0-9-]*——即两个小写字母/数字/连字符组成的段,中间用斜杠分隔,且必须以字母开头。例如my-custom-format/sample-output合法,而doing-it-wrong(缺命名空间)、doing/it/wrong(两个斜杠)、Core/Bold(大写)都会被拒绝;
  • 名称不能与已注册格式重复
  • tagName必须是非空字符串
  • className必须是字符串或null。为null时表示"裸元素"格式(不带 class 的标签),此时该tagName不能已有其他格式注册;为字符串时必须匹配^[_a-zA-Z]+[a-zA-Z0-9_-]*$(以字母开头,后可跟字母、数字、连字符、下划线),且该 class 不能已被其他格式占用;
  • 必须提供title,且为字符串;keywords可选但最多 3 个。

这些校验规则均有对应的单元测试覆盖,见 packages/rich-text/src/test/register-format-type.jsdom.test.js,例如"无命名空间""多斜杠""大写名称""重复 tagName/className"等场景都会断言报错并返回undefined

用数据 store 验证注册结果

已注册的格式类型列表维护在core/rich-text数据 store 中。你可以在浏览器控制台执行以下代码确认自定义格式已生效:

wp.data.select( 'core/rich-text' ).getFormatTypes();

该调用会返回一个包含所有格式类型的数组,其中就包括你刚注册的my-custom-format/sample-output

从源码看,store 的选择器定义在 packages/rich-text/src/store/selectors.js:getFormatTypes基于state.formatTypes返回全部格式;getFormatType( name )按名称精确查找;还有getFormatTypeForBareElementgetFormatTypeForClassName两个辅助选择器,分别用于按裸标签名或 class 名反查格式——这也是注册校验阶段判断"冲突"所依赖的内部机制。写入动作则定义在 packages/rich-text/src/store/actions.js,ADD_FORMAT_TYPES/REMOVE_FORMAT_TYPES对应格式的增删。

Step 2:向工具栏添加按钮

格式注册好之后,下一步是注册一个edit组件,把按钮渲染到界面上。edit属性(见 register-format-type.js 中的WPFormat类型定义)应返回一个组件,让用户与新注册的格式进行交互。

使用RichTextToolbarButton组件更新src/index.js

import { registerFormatType } from '@wordpress/rich-text'; import { RichTextToolbarButton } from '@wordpress/block-editor'; const MyCustomButton = ( props ) => { return ( <RichTextToolbarButton icon="editor-code" title="Sample output" onClick={ () => { console.log( 'toggle format' ); } } /> ); }; registerFormatType( 'my-custom-format/sample-output', { title: 'Sample output', tagName: 'samp', className: null, edit: MyCustomButton, } );

构建并重新加载编辑器后,选中任意包含文本的块(例如段落块),确认新按钮已出现在格式工具栏中。点击按钮,检查控制台是否输出toggle format消息。

如果看不到按钮或消息,请检查:JavaScript 是否正确构建并加载、构建过程有无语法错误、以及控制台是否有报错信息。

edit组件接收的 props

从 bold/index.tsx 的实际实现可以看出,edit组件会收到isActivevalueonChangeonFocus等 props(value为当前的RichTextValueonChange用于提交新的富文本值,isActive表示当前选区是否处于该格式下)。RichTextToolbarButton组件由@wordpress/block-editor包提供,参考文档见 packages/block-editor/README.md。

Step 3:点击按钮应用格式

下一步是让按钮真正对选中文本应用格式。对于本例的<samp>标签来说,格式是二元的——要么选中文本带有该标签,要么没有——因此可以直接使用@wordpress/rich-text包中的toggleFormat方法。

更新src/index.js,改写onClick动作:

import { registerFormatType, toggleFormat } from '@wordpress/rich-text'; import { RichTextToolbarButton } from '@wordpress/block-editor'; const MyCustomButton = ( { isActive, onChange, value } ) => { return ( <RichTextToolbarButton icon="editor-code" title="Sample output" onClick={ () => { onChange( toggleFormat( value, { type: 'my-custom-format/sample-output', } ) ); } } isActive={ isActive } /> ); }; registerFormatType( 'my-custom-format/sample-output', { title: 'Sample output', tagName: 'samp', className: null, edit: MyCustomButton, } );

验证步骤:先构建并重新加载,然后选中一段文本并点击按钮,浏览器中该选区会以与周围文本不同的样式显示(<samp>默认有等宽字体等样式)。你还可以切换到 HTML 视图(代码编辑器Ctrl+Shift+Alt+M)确认选中文本已被<samp>标签包裹。

toggleFormat 的底层工作原理

toggleFormat的实现位于 packages/rich-text/src/toggle-format.js。它的逻辑非常直观:

  1. 调用getActiveFormat( value, format.type )检查当前选区起始处是否存在同类型格式;
  2. 若存在则调用removeFormat移除该格式,并向屏幕阅读器播报 "{title}removed.";
  3. 若不存在则调用applyFormat应用该格式,并播报 "{title}applied."。

getActiveFormat(见 get-active-format.js)内部通过getActiveFormats取回选区起始处的格式列表,再按type匹配查找。applyFormat(见 apply-format.js)则处理了选区折叠(光标无选中)与选区展开两种情形:折叠时若光标正好落在同类型格式中,会把范围扩展到该格式的边界以便更新属性;展开时则会把旧格式从区间内过滤掉,再把新格式插入到合适的位置,最后通过normaliseFormats规范化格式序列。removeFormat(见 remove-format.js)是对称的移除逻辑。

内置格式的toggleFormat调用模式与你的自定义按钮完全一致——bold中就是onChange( toggleFormat( value, { type: name, title } ) )。这意味着自定义格式天生具备与粗体相同的"重复点击切换开/关"行为。

使用 className 定制样式

在注册时使用className选项可以为标签添加自定义 class。例如:

registerFormatType( 'my-custom-format/sample-output', { title: 'Sample output', tagName: 'samp', className: 'my-sample-output', edit: MyCustomButton, } );

然后你可以用该 class 配合自定义 CSS 精确命中该元素并按需美化。注意:注册时className若为字符串,格式匹配将基于该 class;若为null,则代表"裸元素"格式(只按标签名匹配),二者在 store 中是分开维护的(对应getFormatTypeForBareElementgetFormatTypeForClassName两个选择器)。

Step 4:只在特定块类型中显示按钮(可选)

默认情况下,按钮会渲染在每个富文本工具栏上(图片说明、按钮、段落等)。如果希望按钮只出现在特定类型的块上,可以使用 data API(参考 packages/data)结合useSelect读取当前选中的块。

以下示例让按钮仅在段落块(Paragraph)中显示:

import { registerFormatType, toggleFormat } from '@wordpress/rich-text'; import { RichTextToolbarButton } from '@wordpress/block-editor'; import { useSelect } from '@wordpress/data'; function ConditionalButton( { isActive, onChange, value } ) { const selectedBlock = useSelect( ( select ) => { return select( 'core/block-editor' ).getSelectedBlock(); }, [] ); if ( selectedBlock && selectedBlock.name !== 'core/paragraph' ) { return null; } return ( <RichTextToolbarButton icon="editor-code" title="Sample output" onClick={ () => { onChange( toggleFormat( value, { type: 'my-custom-format/sample-output', } ) ); } } isActive={ isActive } /> ); } registerFormatType( 'my-custom-format/sample-output', { title: 'Sample output', tagName: 'samp', className: null, edit: ConditionalButton, } );

这里通过select( 'core/block-editor' ).getSelectedBlock()获取当前选中的块对象,判断其name是否等于core/paragraph;不是则返回null不渲染按钮。你也可以据此扩展出"仅对按钮块、引文块生效"等更细粒度的可见性规则。

Step 5:把按钮放到下拉菜单之外(可选)

使用RichTextToolbarButton时,按钮会被放入默认的下拉菜单中。若想直接把按钮固定显示在工具栏上(不折叠进下拉菜单),可以改用BlockControls组件:

import { registerFormatType, toggleFormat } from '@wordpress/rich-text'; import { BlockControls } from '@wordpress/block-editor'; import { ToolbarGroup, ToolbarButton } from '@wordpress/components'; const MyCustomButton = ( { isActive, onChange, value } ) => { return ( <BlockControls> <ToolbarGroup> <ToolbarButton icon="editor-code" title="Sample output" onClick={ () => { onChange( toggleFormat( value, { type: 'my-custom-format/sample-output', } ) ); } } isActive={ isActive } /> </ToolbarGroup> </BlockControls> ); }; registerFormatType( 'my-custom-format/sample-output', { title: 'Sample output', tagName: 'samp', className: null, edit: MyCustomButton, } );

此时按钮通过BlockControls被渲染到块级工具栏(block toolbar)上,而不是富文本浮层工具栏的下拉菜单中。

Troubleshooting:常见问题排查

如果遇到错误,按以下顺序排查:

  • 确认先运行了npm run build
  • 确认构建过程没有语法错误或其他问题;
  • 确认 JavaScript 确实被加载到了编辑器中(例如在浏览器 Network 面板检查脚本请求,或在控制台打印window.wp相关全局对象);
  • 检查控制台是否有报错信息——尤其注意registerFormatType的名称格式、tagName、className 校验报错(详见上文 Step 1 的校验规则);
  • 若按钮未显示,检查edit组件是否在条件渲染中意外返回了null,以及当前块类型是否符合可见性条件。

更多可用的 RichText API

本指南主要使用了registerFormatTypetoggleFormat@wordpress/rich-text还提供了其他常用 API,完整文档见 packages/rich-text/README.md:

  • applyFormat:把格式对象应用到当前选区的富文本值上,返回新值;
  • removeFormat:按格式类型从选区移除格式;
  • toggleFormat:在应用与移除之间切换(本指南 Step 3 的核心);
  • registerFormatType:注册新格式(Step 1);
  • unregisterFormatType:反注册格式,实现位于 packages/rich-text/src/unregister-format-type.js,若格式未注册会报错并返回undefined

此外,若你的格式需要根据选区定位弹出 UI(如链接格式的输入框),可以借助useAnchorhook(见 packages/rich-text/README.md),它返回当前被格式化的元素,或在无格式活动时为选区范围构造虚拟元素,适合传给Popover组件的anchor属性。

结论

本指南演示了如何向工具栏添加按钮,并让按钮对选中文本应用格式:从registerFormatType注册格式类型、用RichTextToolbarButton渲染按钮、用toggleFormat实现切换,再到按块类型条件渲染与使用BlockControls将按钮固定到工具栏。内置的core/boldcore/italiccore/link等格式(全部定义于 packages/format-library/src/default-formats.ts,并在 packages/format-library/src/index.ts 中批量注册)都是这套机制的直接产物。动手在下一个插件中试试,探索 Format API 能为你带来怎样的编辑体验增强吧。

【免费下载链接】gutenbergThe Block Editor project for WordPress and beyond. Plugin is available from the official repository.项目地址: https://gitcode.com/GitHub_Trending/gu/gutenberg

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/16 20:09:10

SUCTF EasySQL深度解析:堆叠注入与SQL Mode的巧妙利用

SUCTF 2019 的 EasySQL 算是我印象里很典型的一道“名字简单、内核不简单”的 Web 题。网上虽然有很多 Writeup&#xff0c;但不少直接把 Payload 一贴就结束了&#xff0c;新手看完还是不知道为什么要输入1;set sql_modePIPES_AS_CONCAT;select 1。这篇文章我会从零开始&#…

作者头像 李华
网站建设 2026/9/16 20:08:40

OpenRAG默认文档服务详解:示例知识库如何加速新手上手

OpenRAG默认文档服务详解&#xff1a;示例知识库如何加速新手上手 【免费下载链接】openrag OpenRAG is a comprehensive, single package Retrieval-Augmented Generation platform built on Langflow, Docling, and Opensearch. 项目地址: https://gitcode.com/GitHub_Tre…

作者头像 李华
网站建设 2026/9/16 20:08:27

camofox-browser /tabs端点详解:创建、列表、统计、关闭全覆盖

camofox-browser /tabs端点详解&#xff1a;创建、列表、统计、关闭全覆盖 【免费下载链接】camofox-browser Stealth headless browser for AI agents — bypass Cloudflare, bot detection, and anti-scraping. Drop-in Puppeteer/Playwright replacement. 项目地址: https…

作者头像 李华
网站建设 2026/9/16 20:07:35

大模型微调技术实战:核心价值、方法与应用场景

1. 大模型微调的核心价值与适用场景大模型微调&#xff08;Fine-tuning&#xff09;正在成为AI应用落地的关键技术路径。与直接使用基础模型&#xff08;如GPT-4、LLaMA等&#xff09;相比&#xff0c;微调能显著提升模型在特定领域的表现。根据我的实践经验&#xff0c;在医疗…

作者头像 李华