gutenbergdocs/docs/reference-guides/block-api/block-variations.md
2025-10-22 01:40:18 +08:00

248 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 区块变体
区块变体API允许您为区块定义多个版本变体。区块变体通过一组初始属性或内部区块与原始区块区分开来。当您将区块变体插入编辑器时这些属性和/或内部区块会被应用。
变体是在不从头构建全新区块的情况下,创建现有区块迭代版本的绝佳方式。
为了更好地理解此API请以嵌入区块为例。该区块包含多种可嵌入内容类型WordPress、YouTube等的众多变体。每个嵌入区块变体共享相同的底层功能如编辑、保存等。除了名称和描述信息外主要区别在于`providerNameSlug`属性。以下是嵌入区块变体的简化示例。完整规范请查看[源代码](https://github.com/WordPress/gutenberg/blob/trunk/packages/block-library/src/embed/variations.js)。
```js
variations: [
{
name: 'wordpress',
title: 'WordPress',
description: __( '嵌入WordPress文章。' ),
attributes: { providerNameSlug: 'wordpress' },
},
{
name: 'youtube',
title: 'YouTube',
description: __( '嵌入YouTube视频。' ),
attributes: { providerNameSlug: 'youtube' },
},
],
```
## 定义区块变体
区块变体通过包含以下字段的对象定义:
- `name`(类型`string` 唯一且机器可读的名称
- `title`(可选,类型`string` 人类可读的变体标题
- `description`(可选,类型`string` 人类可读的变体描述
- `category`(可选,类型`string`- 在搜索界面中用于按分类排列区块类型的分类标识
- `keywords`(可选,类型`string[]`- 帮助用户在搜索时发现变体的术语数组(可翻译)
- `icon`(可选,类型`string` | `Object` 帮助可视化变体的图标,可与区块类型保持相同样式
- `attributes`(可选,类型`Object` 覆盖区块属性的值
- `innerBlocks`(可选,类型`Array[]` 嵌套区块的初始配置
- `example`(可选,类型`Object` 为区块预览提供结构化数据。设置为`undefined`可禁用预览。详见[区块注册API](/docs/reference-guides/block-api/block-registration.md#example-optional)
- `scope`(可选,类型`WPBlockVariationScope[]`- 默认为`block`和`inserter`。变体适用的作用域列表,可用选项包括:
- `block` - 被区块用于筛选特定区块变体。`Columns`和`Query`区块包含此类变体,这些变体会传递给[实验性BlockVariationPicker](https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/block-variation-picker/README.md)组件,该组件负责显示变体并允许用户选择
- `inserter` - 在插入器中显示区块变体
- `transform` - 在变体转换组件中显示区块变体
- `isDefault`(可选,类型`boolean` 默认为`false`。指示当前变体是否为默认变体(详见下文)
- `isActive`(可选,类型`Function|string[]`- 用于确定选中区块时变体是否处于活动状态的函数或区块属性数组。该函数接受`blockAttributes`和`variationAttributes`参数(详见下文)
<div class="callout callout-info">
从技术上讲,您可以创建没有唯一<code>name</code>的区块变体,但<strong>不推荐</strong>这样做。唯一的<code>name</code>允许编辑器区分您的变体与其他可能存在的变体,还允许在需要时注销您的变体,并对<code>isDefault</code>设置产生影响(详见下文)。
</div>
## 创建区块变体
在区块注册过程中,可通过为`variations`键提供规范的变体对象数组来声明区块变体,如上例所示。更多详细信息请参阅[区块注册API](/docs/reference-guide/block-api/block-registration.md)。
若要为现有区块(如核心区块)创建变体,请使用`wp.blocks.registerBlockVariation()`。该函数接受区块名称和定义变体的对象。
```js
wp.blocks.registerBlockVariation( 'core/embed', {
name: 'custom-embed',
attributes: { providerNameSlug: 'custom' },
} );
```
## 通过PHP注册区块变体
区块变体也可使用`get_block_type_variations`过滤器钩子在PHP中注册。当需要基于已注册的文章类型、分类法或其他WordPress数据动态生成变体时这种方法特别有用。
以下是为`core/image`区块注册自定义变体的示例:
```php
function my_custom_image_variation( $variations, $block_type ) {
// 仅修改图片区块的变体
if ( 'core/image' !== $block_type->name ) {
return $variations;
}
// 添加自定义变体
$variations[] = array(
'name' => 'wide-image',
'title' => __( '宽幅图片', 'textdomain' ),
'description' => __( '宽幅图片', 'textdomain' ),
'scope' => array( 'inserter' ),
'isDefault' => false,
'attributes' => array(
'align' => 'wide', // 标识为自定义链接类型
),
);
return $variations;
}
add_filter( 'get_block_type_variations', 'my_custom_image_variation', 10, 2 );
```
当请求区块类型的变体时会调用`get_block_type_variations`过滤器。它接收两个参数:
- `$variations`:当前已注册的区块类型变体数组
- `$block_type`:完整的区块类型对象
注意通过PHP注册的变体将与使用`registerBlockVariation()`通过JavaScript注册的任何变体合并。
<div class="callout callout-info">查看<a href="https://developer.wordpress.org/news/2024/03/how-to-register-block-variations-with-php/">如何使用PHP注册区块变体</a>博客文章获取更多信息</div>
## 移除区块变体
区块变体也可以轻松移除。为此,请使用`wp.blocks.unregisterBlockVariation()`。该函数接受区块名称和需要注销的变体`name`。
```js
wp.blocks.unregisterBlockVariation( 'core/embed', 'youtube' );
```
## 区块变体与区块样式
区块样式与区块变体的主要区别在于区块样式仅向区块应用CSS类从而能以替代方式进行样式设计。更多详细信息请参阅[区块样式API](/docs/reference-guides/block-api/block-styles.md)。
若要设置初始属性或内部区块,则属于区块变体范畴。在定义区块变体时,也可以通过`className`属性覆盖默认区块样式。
```js
variations: [
{
name: 'blue',
title: __( '蓝色引用' ),
isDefault: true,
attributes: {
color: 'blue',
className: 'is-style-blue-quote'
},
icon: 'format-quote',
isActive: ( blockAttributes, variationAttributes ) =>
blockAttributes.color === variationAttributes.color
},
],
```
## 使用`isDefault`标志
默认情况下,所有变体都会在插入器中与原始区块类型项共同显示。但为列出的任何变体设置`isDefault`标志将覆盖插入器中的常规区块类型。这是根据特定需求定制编辑器体验的强大工具。
例如,若希望媒体与文本区块默认在右侧显示图像,可创建如下变体:
```js
wp.blocks.registerBlockVariation( 'core/media-text', {
name: 'media-text-media-right',
title: __( '媒体与文本' ),
isDefault: true,
attributes: {
mediaPosition: 'right',
},
} );
```
### 使用 `isDefault` 的注意事项
虽然 `isDefault` 在覆盖没有现有变体的区块时效果很好,但当存在其他变体时,您可能会遇到问题。
如果同一区块的另一个变体使用了 `isDefault`,您的变体不一定会成为默认变体。编辑器会尊重第一个注册的带有 `isDefault` 的变体,这可能不是您的变体。
解决方案是在注册带有 `isDefault` 的变体之前,先取消注册其他变体。这一注意事项进一步强调了始终为变体提供唯一 `name` 的建议。否则,该变体将无法被取消注册。
## 使用 `isActive`
虽然 `isActive` 属性是可选的,但建议使用它。区块编辑器使用此 API 来检查哪个变体处于活动状态,并在编辑器中选择该变体的实例时显示正确的变体标题、图标和描述。
如果未设置 `isActive`,编辑器将无法区分原始区块的实例和您的变体,因此将显示原始区块的信息。
该属性可以设置为字符串数组(`string[]`)或函数。建议尽可能使用字符串数组版本。
`string[]` 版本用于声明应将区块实例的哪些属性与给定变体的属性进行比较。每个属性都将被检查,如果所有属性都匹配,则该变体将处于活动状态。
例如,在核心的 Embed 区块中,`providerNameSlug` 属性用于确定嵌入提供程序(例如 “youtube” 或 “twitter”。变体可以这样声明
```js
const variations = [
{
name: 'twitter',
title: 'Twitter',
icon: embedTwitterIcon,
keywords: [ 'tweet', __( 'social' ) ],
description: __( '嵌入推文。' ),
patterns: [ /^https?:\/\/(www\.)?twitter\.com\/.+/i ],
attributes: { providerNameSlug: 'twitter', responsive: true },
},
{
name: 'youtube',
title: 'YouTube',
icon: embedYouTubeIcon,
keywords: [ __( '音乐' ), __( '视频' ) ],
description: __( '嵌入 YouTube 视频。' ),
patterns: [
/^https?:\/\/((m|www)\.)?youtube\.com\/.+/i,
/^https?:\/\/youtu\.be\/.+/i,
],
attributes: { providerNameSlug: 'youtube', responsive: true },
},
// ...
];
```
那么 `isActive` 属性将如下所示:
```js
isActive: [ 'providerNameSlug' ];
```
这将导致区块实例的 `providerNameSlug` 值与变体声明中的值(上述代码片段中的值)进行比较,以确定哪个嵌入变体处于活动状态。
自 WordPress `6.6.0` 起,还支持嵌套对象路径。例如,假设一个区块变体具有 `query` 对象作为属性。可以仅基于该对象的 `postType` 属性(同时忽略其所有其他属性)来确定变体是否处于活动状态:
```js
isActive: [ 'query.postType' ];
```
该属性的函数版本接受区块实例的 `blockAttributes` 作为第一个参数,以及为变体声明的 `variationAttributes` 作为第二个参数。可以通过比较这些参数来确定变体是否处于活动状态,并返回 `true``false`(表示此变体是否对此区块实例处于活动状态)。
以嵌入区块的相同示例为例,函数版本将如下所示:
```js
isActive: ( blockAttributes, variationAttributes ) =>
blockAttributes.providerNameSlug === variationAttributes.providerNameSlug,
```
### `isActive` 匹配的特定性
*注意:自 WordPress `6.6.0` 起改进了处理方式。*
如果有多个变体的 `isActive` 检查匹配给定的区块实例,并且所有变体都是字符串数组,则将选择*特定性*最高的变体。考虑以下示例:
```js
wp.blocks.registerBlockVariation( 'core/paragraph', {
name: 'paragraph-red',
title: '红色段落',
attributes: {
textColor: 'vivid-red',
},
isActive: [ 'textColor' ],
} );
wp.blocks.registerBlockVariation( 'core/paragraph', {
name: 'paragraph-red-grey',
title: '红/灰段落',
attributes: {
textColor: 'vivid-red',
backgroundColor: 'cyan-bluish-gray',
},
isActive: [ 'textColor', 'backgroundColor' ],
} );
```
如果某个区块实例具有属性 `textColor: vivid-red``backgroundColor: cyan-bluish-gray`,则两个变体的 `isActive` 条件都将匹配该区块实例。在这种情况下,将确定*特定性*更高的匹配为活动变体,其中特定性计算为每个 `isActive` 数组的长度。这意味着 `红/灰段落` 将显示为活动变体。
请注意,如果匹配变体的 `isActive` 属性是函数而不是 `string[]`,则无法确定其特定性。在这种情况下,第一个匹配的变体将被确定为活动变体。因此,通常建议为 `isActive` 属性使用 `string[]` 而不是 `function`