Gutenberg FontFamilyControl 组件实战:基于 typography.fontFamilies 预设的字体族选择器
【免费下载链接】gutenbergThe Block Editor project for WordPress and beyond. Plugin is available from the official repository.项目地址: https://gitcode.com/GitHub_Trending/gu/gutenberg
导读
FontFamilyControl是 Gutenberg 块编辑器(@wordpress/block-editor包)提供的一个 React 组件,它渲染一个下拉选择控件,让用户在编辑器侧边栏或自定义块设置面板中挑选字体族。该组件的核心数据来源是全局样式(Global Styles)中的typography.fontFamilies预设,并允许通过fontFamiliesprop 覆盖预设值。阅读完本文,你将掌握该组件的完整 Props 契约、在自定义块与全局样式排版面板中的接入方式,以及它在仓库源码中的真实实现与设置解析链路。
实验性功能警告:该组件当前仍处于实验阶段(experimental)。“实验性”意味着它是早期实现,未来可能发生大幅度的破坏性变更,在生产环境中使用时请关注版本升级日志。
FontFamilyControl 是什么
FontFamilyControl渲染一个用于选择字体族的用户界面,用户可以从由typography.fontFamilies预设定义的一组预置字体族中选择其一。可选地,你可以通过fontFamiliesprop 传入自定义字体族集合,从而覆盖预置字体族。
在仓库中,该组件位于 packages/block-editor/src/components/font-family/index.jsx,并从包入口 packages/block-editor/src/components/index.js 以实验性 API 形式导出:
export { default as __experimentalFontFamilyControl } from './font-family';因此在业务代码中通常这样引入:
import { __experimentalFontFamilyControl as FontFamilyControl } from '@wordpress/block-editor';基本用法
在自定义块(Block)的edit函数中,配合useState使用即可实现一个受控的字体族选择器:
import { useState } from 'react'; import { __experimentalFontFamilyControl as FontFamilyControl } from '@wordpress/block-editor'; import { __ } from '@wordpress/i18n'; // ... const MyFontFamilyControl = () => { const [ fontFamily, setFontFamily ] = useState( '' ); return ( <FontFamilyControl value={ fontFamily } onChange={ ( newFontFamily ) => { setFontFamily( newFontFamily ); } } /> ); }; // ... <MyFontFamilyControl />核心要点:
value初始值为空字符串'',此时下拉框默认显示 “Default”(默认)选项;onChange会在用户选中某个字体族后收到新的字体族值(即对应的fontFamilyCSS 值);- 当用户选择 “Default” 时,
onChange会被调用但不带任何参数(见下文 Props 说明),业务侧应根据该语义执行“重置”逻辑。
Props 契约
组件接受以下 Props:
onChange(必填)
接收新字体族值的回调函数。
- 类型:
function - 必填:是
如果onChange被调用且未携带任何参数,则应当重置该值——具体“重置”的语义由使用场景决定,例如将字体族设为undefined,或恢复为某个起始值。
fontFamilies(可选)
用户提供的字体族集合,用于覆盖来自预设(presets)的预置字体族。
- 类型:
Array - 必填:否
字体族以对象数组形式提供,schema 如下:
| 属性 | 描述 | 类型 |
|---|---|---|
fontFamily | 字体族,用法与 CSS 中的取值一致 | string |
name | 字体族的可选显示名称 | string |
例如:
const fontFamilies = [ { fontFamily: '"Inter", sans-serif', name: 'Inter' }, { fontFamily: '-apple-system,system-ui,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif', name: 'System Font', }, ];仓库中的 Storybook 示例 packages/block-editor/src/components/font-family/stories/index.story.jsx 展示了更贴近真实场景的数据结构——除了fontFamily与name外,还可以携带slug以及fontFace(字面量fontFamily描述 +src字体文件地址等),例如:
{ fontFace: [ { fontFamily: 'Inter', fontStretch: 'normal', fontStyle: 'normal', fontWeight: '200 900', src: [ 'file:./assets/fonts/inter/Inter-VariableFont_slnt,wght.ttf' ], }, ], fontFamily: '"Inter", sans-serif', name: 'Inter', slug: 'inter', }value(可选)
当前字体族的值。
- 类型:
String - 必填:否
- 默认值:
''
其他 Props
其余所有未列出的 Props 都会被透传(spread)给底层的CustomSelectControl实例,例如label、className、size等均可按需覆盖。
源码级实现剖析
FontFamilyControl的实现非常精简,完整逻辑集中在 packages/block-editor/src/components/font-family/index.jsx 一个文件中,可拆解为以下四个步骤:
1. 读取全局设置中的预设字体族
const [ blockLevelFontFamilies ] = useSettings( 'typography.fontFamilies' ); if ( ! fontFamilies ) { fontFamilies = blockLevelFontFamilies; }组件通过useSettings( 'typography.fontFamilies' )从块编辑上下文中读取设置。useSettings的实现见 packages/block-editor/src/components/use-settings/index.js:它会先基于当前块的clientId,在块实例层级链中向上查找设置;找不到时再回退到块编辑器的全局设置。其底层委托给 store 的私有选择器getBlockSettings(packages/block-editor/src/store/get-block-settings.js),后者会沿着块层级向上遍历,并收集所有声明了__experimentalSettings块支持的祖先块设置。这也意味着:主题或父级块在typography.fontFamilies中定义的预设会自动成为该下拉框的数据源。
2. 空数据保护
if ( ! fontFamilies || fontFamilies.length === 0 ) { return null; }当没有任何预设字体族时,组件直接渲染null——因此不会出现一个空的下拉框。
3. 组装选项列表
const options = [ { key: '', name: __( 'Default' ), }, ...fontFamilies.map( ( { fontFamily, name } ) => ( { key: fontFamily, name: name || fontFamily, style: { fontFamily }, } ) ), ];- 第一项固定为
key: ''、显示名 “Default”,即“跟随默认/重置”选项; - 每个预设字体族映射为一个选项,
key使用fontFamily的 CSS 值,name优先取name字段、缺省时回退为fontFamily; - 每个选项还附带
style: { fontFamily },因此下拉列表中的每一项会以自身字体渲染,让用户直观预览字体效果。
4. 渲染 CustomSelectControl
const selectedValue = options.find( ( option ) => option.key === value ) ?? ''; return ( <CustomSelectControl label={ __( 'Font' ) } value={ selectedValue } onChange={ ( { selectedItem } ) => onChange( selectedItem.key ) } options={ options } className={ clsx( 'block-editor-font-family-control', className ) } { ...props } /> );- 底层实际是
@wordpress/components的CustomSelectControl,默认 label 为 “Font”; selectedValue根据传入的value在选项中查找对应项;若未找到(例如value不在预设中),回退为'';- 选中项通过
onChange( selectedItem.key )回传。特别地,当选中 “Default” 项时selectedItem.key为'',即对应 README 中“无参数调用时表示重置”的语义约定(在实现层面表现为回调''空字符串); - 自定义
className会与内置的block-editor-font-family-control合并。
在全局样式排版面板中的真实调用
FontFamilyControl并非孤立组件,它在编辑器内置的“排版(Typography)”全局样式面板中被实际使用,位置在 packages/block-editor/src/components/global-styles/typography-panel.jsx:
<FontFamilyControl fontFamilies={ fontFamilies } value={ fontFamily } onChange={ setFontFamily } />调用上下文要点:
- 只有当设置
settings.typography.fontFamilies中存在至少一个字体族(useHasFontFamilyControl会逐项检查各字体的长度,见同文件第 112-115 行)时,该控件才会渲染; - 它被包裹在
InheritanceToolsPanelItem中,支持“继承”语义与重置(onDeselect={ resetFontFamily }); - 面板通过
useMemo将settings.typography.fontFamilies处理成fontFamilies数据(含fontFamily与name),直接喂给组件。
这为自定义块接入提供了范本:将组件嵌入你自己的InspectorControls或面板,并维护好value/onChange即可。
与 theme.json 预设的关联
typography.fontFamilies预设通常由主题的theme.json定义。在根目录的 lib/theme.json 中即可找到 Gutenberg 插件自身使用的字体预设配置。数据结构与组件期望的 schema 完全对应:
"typography": { "fontFamilies": [ { "fontFamily": "var(--wp--preset--font-family--system-font)", "name": "系统字体", "slug": "system-font" } ] }这意味着:主题开发者只需在theme.json的settings.typography.fontFamilies中声明字体族(fontFamily、name、slug,可选fontFace),FontFamilyControl便会自动把这些字体呈现为可选项,无需在组件层重复声明——这正是“预设优先、prop 覆盖”设计的意义所在。
总结与注意事项
- 接入方式:以
__experimentalFontFamilyControl命名从@wordpress/block-editor导出,作为受控组件使用,必填onChange,可选value与fontFamilies; - 数据流:未传
fontFamilies时自动读取typography.fontFamilies设置(块级覆盖全局,回退到编辑器设置),为空时渲染null; - 选项语义:内置 “Default” 项(key 为
''),选中它即代表“重置”,onChange回调'';其余选项 key 为字体族的 CSS 值,并以name(缺省回退fontFamily)为显示名,且每项按自身字体族渲染预览; - 透传机制:其余 props 直接透传给底层
CustomSelectControl,可进一步定制 label、className 等; - 实验性风险:组件仍为实验性 API,未来版本可能调整 Props 或导出命名(例如当前实现已移除
__next40pxDefaultSize迁移 prop,该 prop 自 WordPress 7.1 起已默认生效,代码中标记为 deprecated),升级依赖时请留意变更日志。
仓库内可供进一步研读的相关文件:
- 组件实现
- 组件 README
- Storybook 示例
- 包导出入口
- 设置读取 Hook useSettings
- 设置解析选择器 getBlockSettings
- 全局样式排版面板中的调用
- Gutenberg 插件自身的字体预设配置
【免费下载链接】gutenbergThe Block Editor project for WordPress and beyond. Plugin is available from the official repository.项目地址: https://gitcode.com/GitHub_Trending/gu/gutenberg
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考