## `ungroup` 区块解组功能 通过区块配置中可选的 `transforms` 键,区块可使用 `ungroup` 子键定义用于替换当前处理区块的新区块。这些新区块通常是现有内部区块的子集,但也可包含全新区块。 若某区块配置了 `ungroup` 转换功能,即具备解组资格,无需作为默认分组区块即可使用。通过此 API 解组区块的用户界面与默认分组区块所用的界面相同。需满足以下条件才会显示解组按钮:必须选中单个分组区块,且该区块需包含若干内部区块。 **ungroup** 是一个回调函数,接收被处理区块的属性及内部区块数据,需返回区块对象数组。 示例: ```js export const settings = { title: '我的分组区块标题', description: '我的分组区块描述', /* ... */ transforms: { ungroup: ( attributes, innerBlocks ) => innerBlocks.flatMap( ( innerBlock ) => innerBlock.innerBlocks ), }, }; ``` 当我们成功匹配此内容时,除 `data-post-id` 外所有HTML属性都将被剥离。如果给定 `div` 内存在其他HTML排列方式,则无法匹配转换器。同理,若其中出现的是 `

` 而非 `

`,匹配也会失败。 在处理包含非短语内容(如带 `` 的 `
`)的HTML片段时,模式定义至关重要。若未声明自定义模式,编辑器在尝试通过任何区块转换前会跳过这些特殊结构。 ### 短代码 此类转换支持单向转换(从短代码创建区块),作为 `raw` 转换流程的组成部分。 `shortcode` 类型转换对象包含以下参数: - **type** _(字符串)_:固定值 `shortcode` - **tag** _(字符串|数组)_:可转换的短代码标签或别名列表 - **transform** _(函数,可选)_:接收短代码属性(首参数)与 [WPShortcodeMatch](/packages/shortcode/README.md#next)(次参数)的回调函数,应返回区块对象或区块对象数组。定义此参数时将优先于 `attributes` 参数 - **attributes** _(对象,可选)_:根据[区块配置对象](/docs/reference-guides/block-api/block-registration.md)定义的属性结构,指定区块属性来源。若某属性包含 `shortcode` 键,则应为接收短代码属性(首参数)与 [WPShortcodeMatch](/packages/shortcode/README.md#next)(次参数)的函数,并返回将存入区块注释的属性值 - **isMatch** _(函数,可选)_:根据 [Shortcode API](https://codex.wordpress.org/Shortcode_API) 接收短代码属性的回调函数,应返回布尔值。返回 `false` 将阻止该短代码转换为此区块 - **priority** _(数字,可选)_:控制转换应用优先级,数值较低者优先,工作机制类似 [WordPress 钩子](https://developer.wordpress.org/reference/#Hook_to_WordPress)。如未设置,默认优先级为 `10` **示例:通过 `transform` 从短代码转换为区块** 使用 `transform` 方法可将现有短代码转换为其对应区块: ```js transforms: { from: [ { type: 'shortcode', tag: 'video', transform( { named: { src } } ) { return createBlock( 'core/video', { src } ); }, // 当短代码不具备正确ID时 // 阻止其转换为此区块 isMatch( { named: { id } } ) { return id === 'my-id'; }, }, ], }, ``` **示例:通过 `attributes` 从短代码转换为区块** 使用 `attributes` 参数可将现有短代码转换为其对应区块: ```js 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` 分别存储不同方向的转换数组。例如: ```js 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钩子](https://developer.wordpress.org/reference/#Hook_to_WordPress),默认优先级为 `10` **示例:从段落区块转换为标题区块** 在标题区块配置中添加以下代码(使用 [`wp-blocks` 包](/packages/blocks/README.md#createBlock) 的 `createBlock` 函数): ```js transforms: { from: [ { type: 'block', blocks: [ 'core/paragraph' ], transform: ( { content } ) => { return createBlock( 'core/heading', { content, } ); }, }, ] }, ``` **示例:含内部区块的转换** 具有InnerBlocks的区块可与其他含内部区块的区块相互转换: ```js 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钩子](https://developer.wordpress.org/reference/#Hook_to_WordPress),默认优先级为 `10` **示例:通过 --- 创建分隔符区块** 当用户输入三个连字符后按回车键时创建分隔符区块: ```js transforms = { from: [ { type: 'enter', regExp: /^-{3,}$/, transform: () => createBlock( 'core/separator' ), }, ], }; ``` ### 文件类型转换 此类转换支持 _from_ 方向,允许通过将文件拖拽至编辑器来创建区块。 `files` 类型的转换是一个包含以下参数的对象: - **type**(字符串):取值为 `files` - **transform**(函数):接收正在处理的文件数组的回调函数,应返回区块对象或区块对象数组 - **isMatch**(函数,可选):接收正在处理的文件数组的回调函数,应返回布尔值。返回 `false` 将阻止应用此转换 - **priority**(数字,可选):控制转换应用的优先级,数值较低的优先级高于数值较高的优先级。其行为类似于 [WordPress 钩子](https://developer.wordpress.org/reference/#Hook_to_WordPress)。与钩子类似,未设置时的默认优先级为 `10` **示例:从文件创建文件区块** 当用户将文件拖拽至编辑器时,可通过以下代码创建文件区块: ```js 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 钩子](https://developer.wordpress.org/reference/#Hook_to_WordPress)。与钩子类似,未设置时的默认优先级为 `10` **示例:从文本创建自定义区块** 若要在用户输入问号时创建自定义区块,可使用以下代码: ```js transforms: { from: [ { type: 'prefix', prefix: '?', transform( content ) { return createBlock( 'my-plugin/question', { content, } ); }, }, ]; } ``` ### 原始内容类型转换 此类转换支持 _from_ 方向,允许根据原始 HTML 节点创建区块。当用户执行区块设置界面菜单中的"转换为区块"操作,或向编辑器粘贴/拖拽内容时触发。 `raw` 类型的转换是一个包含以下参数的对象: - **type**(字符串):取值为 `raw` - **transform**(函数,可选):接收正在处理节点的回调函数,应返回区块对象或区块对象数组 - **schema**(对象|函数,可选):定义用于检测和处理粘贴内容的 [HTML 内容模型](https://html.spec.whatwg.org/multipage/dom.html#content-models),详见[下文](#内容模型与架构) - **selector**(字符串,可选):用于根据 [element.matches](https://developer.mozilla.org/en-US/docs/Web/API/Element/matches) 方法判断元素是否匹配的 CSS 选择器字符串。若元素不匹配则不会执行转换。这是 `isMatch` 的简写替代方案,若同时存在则优先使用 `isMatch` - **isMatch**(函数,可选):接收正在处理节点的回调函数,应返回布尔值。返回 `false` 将阻止应用此转换 - **priority**(数字,可选):控制转换应用的优先级,数值较低的优先级高于数值较高的优先级。其行为类似于 [WordPress 钩子](https://developer.wordpress.org/reference/#Hook_to_WordPress)。与钩子类似,未设置时的默认优先级为 `10` **示例:从 URL 创建嵌入区块** 若要在用户向编辑器粘贴 URL 时创建嵌入区块,可使用以下代码: ```js 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(), } ); }, }, ], } ```

内容模型与架构

在粘贴内容时,可以定义用于验证和处理粘贴内容的[内容模型](https://html.spec.whatwg.org/multipage/dom.html#content-models)。粘贴到编辑器中的 HTML 通常包含应当转移和不应转移的混合元素。例如考虑将 `12:04 pm` 粘贴到编辑器中的情况:我们需要复制 `12:04 pm` 并忽略 `` 及其 `class` 属性,因为这些元素在复制后不再具有原有的含义和结构。 在编写 `raw` 转换时,可通过提供描述允许内容的 `schema` 来控制此行为,该架构将在尝试与区块匹配之前对粘贴内容进行清理。这些架构会传入 [`@wordpress/dom` 中的 `cleanNodeList`](https://github.com/wordpress/gutenberg/blob/trunk/packages/dom/src/dom/clean-node-list.js);请查阅该处获取[架构的完整描述](https://github.com/wordpress/gutenberg/blob/trunk/packages/dom/src/phrasing-content.js)。 ```js schema = { span: { children: { '#text': {} } } }; ``` **示例:自定义内容模型** 假设我们需要匹配以下 HTML 片段并将其转换为某种自定义文章预览区块: ```html

文章标题

一段精彩内容

``` 我们需要通过提供以下架构来告知编辑器允许内部的 `h2` 和 `p` 元素。此示例中使用函数形式,该函数接收包含 `phrasingContentSchema` 的参数(以及指示转换操作是否以粘贴文本开始的布尔值 `isPaste`)。`phrasingContentSchema` 预定义为匹配 HTML 短语元素,如 ``、`` 和 ``。任何期望使用 `` 组件的地方都适合允许短语内容,否则在转换过程中将丢失所有文本格式。 ```js schema = ({ phrasingContentSchema }) => { div: { required: true, attributes: [ 'data-post-id' ], children: { h2: { children: phrasingContentSchema }, p: { children: phrasingContentSchema } } } } ```