15 KiB
ungroup 区块解组功能
通过区块配置中可选的 transforms 键,区块可使用 ungroup 子键定义用于替换当前处理区块的新区块。这些新区块通常是现有内部区块的子集,但也可包含全新区块。
若某区块配置了 ungroup 转换功能,即具备解组资格,无需作为默认分组区块即可使用。通过此 API 解组区块的用户界面与默认分组区块所用的界面相同。需满足以下条件才会显示解组按钮:必须选中单个分组区块,且该区块需包含若干内部区块。
ungroup 是一个回调函数,接收被处理区块的属性及内部区块数据,需返回区块对象数组。
示例:
export const settings = {
title: '我的分组区块标题',
description: '我的分组区块描述',
/* ... */
transforms: {
ungroup: ( attributes, innerBlocks ) =>
innerBlocks.flatMap( ( innerBlock ) => innerBlock.innerBlocks ),
},
};
当我们成功匹配此内容时,除 data-post-id 外所有HTML属性都将被剥离。如果给定 div 内存在其他HTML排列方式,则无法匹配转换器。同理,若其中出现的是 <h3> 而非 <h2>,匹配也会失败。
在处理包含非短语内容(如带 <summary> 的 <details>)的HTML片段时,模式定义至关重要。若未声明自定义模式,编辑器在尝试通过任何区块转换前会跳过这些特殊结构。
短代码
此类转换支持单向转换(从短代码创建区块),作为 raw 转换流程的组成部分。
shortcode 类型转换对象包含以下参数:
- type (字符串):固定值
shortcode - tag (字符串|数组):可转换的短代码标签或别名列表
- transform (函数,可选):接收短代码属性(首参数)与 WPShortcodeMatch(次参数)的回调函数,应返回区块对象或区块对象数组。定义此参数时将优先于
attributes参数 - attributes (对象,可选):根据区块配置对象定义的属性结构,指定区块属性来源。若某属性包含
shortcode键,则应为接收短代码属性(首参数)与 WPShortcodeMatch(次参数)的函数,并返回将存入区块注释的属性值 - isMatch (函数,可选):根据 Shortcode API 接收短代码属性的回调函数,应返回布尔值。返回
false将阻止该短代码转换为此区块 - priority (数字,可选):控制转换应用优先级,数值较低者优先,工作机制类似 WordPress 钩子。如未设置,默认优先级为
10
示例:通过 transform 从短代码转换为区块
使用 transform 方法可将现有短代码转换为其对应区块:
transforms: {
from: [
{
type: 'shortcode',
tag: 'video',
transform( { named: { src } } ) {
return createBlock( 'core/video', { src } );
},
// 当短代码不具备正确ID时
// 阻止其转换为此区块
isMatch( { named: { id } } ) {
return id === 'my-id';
},
},
],
},
示例:通过 attributes 从短代码转换为区块
使用 attributes 参数可将现有短代码转换为其对应区块:
transforms: {
from: [
{
type: 'shortcode',
tag: 'youtube',
attributes: {
url: {
type: 'string',
source: 'attribute',
attribute: 'src',
selector: 'img',
},
align: {
type: 'string',
// 短代码函数将提取短代码属性
// 转换为可存入区块注释的值
shortcode: ( { named: { align = 'alignnone' } } ) => {
return align.replace( 'align', '' );
},
},
},
// 当短代码不具备正确ID时
// 阻止其转换为此区块
isMatch( { named: { id } } ) {
return id === 'my-id';
},
},
]
},
转换功能
区块转换是一套API,允许区块与其他区块进行相互转换,同时也支持从其他实体转换为区块。与此API兼容的现有实体包括短代码、文件、正则表达式和原始DOM节点。
转换方向:to 与 from
区块通过配置项中可选的 transforms 键来声明支持的转换类型,其子键 to 和 from 分别存储不同方向的转换数组。例如:
export const settings = {
title: '我的区块标题',
description: '我的区块描述',
/* ... */
transforms: {
from: [
/* 支持的来源转换 */
],
to: [
/* 支持的目标转换 */
],
},
};
转换类型
本节将介绍区块支持的现有转换类型:
- block(区块)
- enter(回车)
- files(文件)
- prefix(前缀)
- raw(原始)
- shortcode(短代码)
区块转换
此类转换支持双向转换,允许区块转换为其他类型的区块。在区块工具栏中有对应的UI控件。
block 类型的转换对象包含以下参数:
- type(字符串):值为
block - blocks(数组):已知区块类型列表。支持通配符值(
"*"),表示该转换适用于所有区块类型(例如:所有区块都能转换为core/group) - transform(函数):接收被处理区块属性及内部区块的回调函数,应返回区块对象或区块对象数组
- isMatch(函数,可选):接收区块属性(第一参数)和区块对象(第二参数)的回调函数,应返回布尔值。返回
false将隐藏该转换选项 - isMultiBlock(布尔值,可选):是否支持多选区块转换。为true时,
transform函数的首个参数为属性数组,第二参数为内部区块数组。默认为false - priority(数字,可选):控制转换优先级,数值越低优先级越高。行为类似WordPress钩子,默认优先级为
10
示例:从段落区块转换为标题区块
在标题区块配置中添加以下代码(使用 wp-blocks 包 的 createBlock 函数):
transforms: {
from: [
{
type: 'block',
blocks: [ 'core/paragraph' ],
transform: ( { content } ) => {
return createBlock( 'core/heading', {
content,
} );
},
},
]
},
示例:含内部区块的转换
具有InnerBlocks的区块可与其他含内部区块的区块相互转换:
transforms: {
to: [
{
type: 'block',
blocks: [ 'some/block-with-innerblocks' ],
transform: ( attributes, innerBlocks ) => {
return createBlock(
'some/other-block-with-innerblocks',
attributes,
innerBlocks
);
},
},
],
},
回车转换
此类转换仅支持来源转换,允许根据用户输入内容创建区块。当用户输入内容后按回车键时,将在新行中触发转换。
enter 类型的转换对象包含以下参数:
- type(字符串):值为
enter - regExp(正则表达式):用于匹配的正则表达式,匹配成功则触发转换
- transform(函数):接收包含输入内容的回调函数,应返回区块对象或区块对象数组
- priority(数字,可选):控制转换优先级,数值越低优先级越高。行为类似WordPress钩子,默认优先级为
10
示例:通过 --- 创建分隔符区块
当用户输入三个连字符后按回车键时创建分隔符区块:
transforms = {
from: [
{
type: 'enter',
regExp: /^-{3,}$/,
transform: () => createBlock( 'core/separator' ),
},
],
};
文件类型转换
此类转换支持 from 方向,允许通过将文件拖拽至编辑器来创建区块。
files 类型的转换是一个包含以下参数的对象:
- type(字符串):取值为
files - transform(函数):接收正在处理的文件数组的回调函数,应返回区块对象或区块对象数组
- isMatch(函数,可选):接收正在处理的文件数组的回调函数,应返回布尔值。返回
false将阻止应用此转换 - priority(数字,可选):控制转换应用的优先级,数值较低的优先级高于数值较高的优先级。其行为类似于 WordPress 钩子。与钩子类似,未设置时的默认优先级为
10
示例:从文件创建文件区块
当用户将文件拖拽至编辑器时,可通过以下代码创建文件区块:
transforms: {
from: [
{
type: 'files',
isMatch: ( files ) => files.length === 1,
// 通过定义低于默认值10的优先级,
// 使其在没有找到其他转换时作为备用方案创建文件区块
priority: 15,
transform: ( files ) => {
const file = files[ 0 ];
const blobURL = createBlobURL( file );
// 文件将在 componentDidMount() 中上传
return createBlock( 'core/file', {
href: blobURL,
fileName: file.name,
textLinkHref: blobURL,
} );
},
},
];
}
前缀类型转换
此类转换支持 from 方向,允许根据用户输入的文本创建区块。当用户在新区块行中输入文本并添加尾随空格时触发。
prefix 类型的转换是一个包含以下参数的对象:
- type(字符串):取值为
prefix - prefix(字符串):匹配此转换的字符或字符序列
- transform(函数):接收输入内容的回调函数,应返回区块对象或区块对象数组
- priority(数字,可选):控制转换应用的优先级,数值较低的优先级高于数值较高的优先级。其行为类似于 WordPress 钩子。与钩子类似,未设置时的默认优先级为
10
示例:从文本创建自定义区块
若要在用户输入问号时创建自定义区块,可使用以下代码:
transforms: {
from: [
{
type: 'prefix',
prefix: '?',
transform( content ) {
return createBlock( 'my-plugin/question', {
content,
} );
},
},
];
}
原始内容类型转换
此类转换支持 from 方向,允许根据原始 HTML 节点创建区块。当用户执行区块设置界面菜单中的"转换为区块"操作,或向编辑器粘贴/拖拽内容时触发。
raw 类型的转换是一个包含以下参数的对象:
- type(字符串):取值为
raw - transform(函数,可选):接收正在处理节点的回调函数,应返回区块对象或区块对象数组
- schema(对象|函数,可选):定义用于检测和处理粘贴内容的 HTML 内容模型,详见下文
- selector(字符串,可选):用于根据 element.matches 方法判断元素是否匹配的 CSS 选择器字符串。若元素不匹配则不会执行转换。这是
isMatch的简写替代方案,若同时存在则优先使用isMatch - isMatch(函数,可选):接收正在处理节点的回调函数,应返回布尔值。返回
false将阻止应用此转换 - priority(数字,可选):控制转换应用的优先级,数值较低的优先级高于数值较高的优先级。其行为类似于 WordPress 钩子。与钩子类似,未设置时的默认优先级为
10
示例:从 URL 创建嵌入区块
若要在用户向编辑器粘贴 URL 时创建嵌入区块,可使用以下代码:
transforms: {
from: [
{
type: 'raw',
isMatch: ( node ) =>
node.nodeName === 'P' &&
/^\s*(https?:\/\/\S+)\s*$/i.test( node.textContent ),
transform: ( node ) => {
return createBlock( 'core/embed', {
url: node.textContent.trim(),
} );
},
},
],
}
内容模型与架构
在粘贴内容时,可以定义用于验证和处理粘贴内容的内容模型。粘贴到编辑器中的 HTML 通常包含应当转移和不应转移的混合元素。例如考虑将 <span class="time">12:04 pm</span> 粘贴到编辑器中的情况:我们需要复制 12:04 pm 并忽略 <span> 及其 class 属性,因为这些元素在复制后不再具有原有的含义和结构。
在编写 raw 转换时,可通过提供描述允许内容的 schema 来控制此行为,该架构将在尝试与区块匹配之前对粘贴内容进行清理。这些架构会传入 @wordpress/dom 中的 cleanNodeList;请查阅该处获取架构的完整描述。
schema = { span: { children: { '#text': {} } } };
示例:自定义内容模型
假设我们需要匹配以下 HTML 片段并将其转换为某种自定义文章预览区块:
<div data-post-id="13">
<h2>文章标题</h2>
<p>一段<em>精彩</em>内容</p>
</div>
我们需要通过提供以下架构来告知编辑器允许内部的 h2 和 p 元素。此示例中使用函数形式,该函数接收包含 phrasingContentSchema 的参数(以及指示转换操作是否以粘贴文本开始的布尔值 isPaste)。phrasingContentSchema 预定义为匹配 HTML 短语元素,如 <strong>、<sup> 和 <kbd>。任何期望使用 <RichText /> 组件的地方都适合允许短语内容,否则在转换过程中将丢失所有文本格式。
schema = ({ phrasingContentSchema }) => {
div: {
required: true,
attributes: [ 'data-post-id' ],
children: {
h2: { children: phrasingContentSchema },
p: { children: phrasingContentSchema }
}
}
}