gutenbergdocs/reference-guides/slotfills/README.md
2025-10-22 01:33:45 +08:00

368 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.

## 当前可用的 SlotFill 及示例
以下 SlotFill 可在 `edit-post``editor` 包中使用。具体用法及示例请参阅下列各项:
- [主仪表板按钮](/docs/reference-guides/slotfills/main-dashboard-button.md)
- [插件区块设置菜单项](/docs/reference-guides/slotfills/plugin-block-settings-menu-item.md)
- [插件文档设置面板](/docs/reference-guides/slotfills/plugin-document-setting-panel.md)
- [插件更多菜单项](/docs/reference-guides/slotfills/plugin-more-menu-item.md)
- [插件文章发布后面板](/docs/reference-guides/slotfills/plugin-post-publish-panel.md)
- [插件文章状态信息](/docs/reference-guides/slotfills/plugin-post-status-info.md)
- [插件文章发布前面板](/docs/reference-guides/slotfills/plugin-pre-publish-panel.md)
- [插件侧边栏](/docs/reference-guides/slotfills/plugin-sidebar.md)
- [插件侧边栏更多菜单项](/docs/reference-guides/slotfills/plugin-sidebar-more-menu-item.md)
# SlotFills 参考文档
Slot插槽与 Fill填充是已公开的组件允许开发者将项目注入到 Gutenberg 管理体验中的某些预定义位置。
更多详细信息请参阅 [SlotFill 组件文档](/packages/components/src/slot-fill/README.md)。
要使用这些组件,我们必须利用 [@wordpress/plugins](/packages/plugins/README.md) API 注册一个用于注入项目的插件。
## 使用概览
使用 SlotFills 需要完成以下四个步骤:
1.`@wordpress/plugins` 包导入 `registerPlugin` 方法
2.`@wordpress/editor` 包导入所需的 SlotFill 组件
3. 定义渲染内容的组件。需将修改/新增内容包裹在导入的 SlotFill 组件中
4. 注册插件
以下是通过 `PluginPostStatusInfo` 插槽填充的示例:
```js
import { registerPlugin } from '@wordpress/plugins';
import { PluginPostStatusInfo } from '@wordpress/editor';
const PluginPostStatusInfoTest = () => (
<PluginPostStatusInfo>
<p>文章状态信息插槽填充</p>
</PluginPostStatusInfo>
);
registerPlugin( 'post-status-info-test', { render: PluginPostStatusInfoTest } );
```
## 条件化渲染 SlotFill 内容
除 [MainDashboardButton](/docs/reference-guides/slotfills/main-dashboard-button.md) 外,所有可用的 SlotFill 同时在文章编辑器和站点编辑器中公开,任何已注册的 Fill 都会在两种上下文中渲染。可通过多种方式实现条件化渲染。
### 限定填充内容至文章编辑器
通过检查当前文章类型对象的 `viewable` 属性是否为 `true`,可将填充内容限定在文章编辑器内。未设置为 `viewable` 的文章类型没有关联的文章编辑界面,这是判断用户不在文章编辑器中的有效依据。以下示例将在所有已注册文章类型的编辑界面中渲染内容:
```js
/**
* WordPress 依赖项
*/
import { registerPlugin } from '@wordpress/plugins';
import {
PluginDocumentSettingPanel,
store as editorStore,
} from '@wordpress/editor';
import { store as coreStore } from '@wordpress/core-data';
import { useSelect } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
/**
* 作为插件组成部分的渲染组件
*/
const EditPostDocumentSettingPanel = () => {
// 获取当前文章类型信息
const isViewable = useSelect( ( select ) => {
const postTypeName = select( editorStore ).getCurrentPostType();
const postTypeObject = select( coreStore ).getPostType( postTypeName );
return postTypeObject?.viewable;
}, [] );
// 若文章类型不可查看,则不渲染填充内容
if ( ! isViewable ) {
return null;
}
return (
<PluginDocumentSettingPanel
name="custom-panel"
title={ __( '文章编辑器示例' ) }
className="custom-panel"
>
<p>{ __( '仅出现在文章编辑界面' ) }</p>
</PluginDocumentSettingPanel>
);
};
registerPlugin( 'example-post-edit-only', {
render: EditPostDocumentSettingPanel,
} );
```
### 限定填充内容至特定文章类型
以下示例在前例基础上创建允许渲染的文章类型白名单。此处填充内容仅在编辑页面时渲染:
```js
/**
* WordPress 依赖项
*/
import { registerPlugin } from '@wordpress/plugins';
import {
PluginDocumentSettingPanel,
store as editorStore,
} from '@wordpress/editor';
import { store as coreStore } from '@wordpress/core-data';
import { useSelect } from '@wordpress/data';
import { __, sprintf } from '@wordpress/i18n';
/**
* 作为插件组成部分的渲染组件
*/
const RestrictPostTypes = () => {
// 获取当前文章类型信息
const { isViewable, postTypeName } = useSelect( ( select ) => {
const postType = select( editorStore ).getCurrentPostType();
const postTypeObject = select( coreStore ).getPostType( postType );
return {
isViewable: postTypeObject?.viewable,
postTypeName: postType,
};
}, [] );
// 允许渲染插件的文章类型列表
const allowedPostTypes = [ 'page' ];
// 若文章类型不可查看或不在允许列表中,则不渲染插件
if ( ! isViewable || ! allowedPostTypes.includes( postTypeName ) ) {
return null;
}
return (
<PluginDocumentSettingPanel
name="custom-panel"
title={ __( '文章类型限制示例' ) }
className="custom-panel"
>
<p>
{ sprintf(
__(
'仅出现在允许列表中的文章类型上。%s'
),
allowedPostTypes.join( ', ' )
) }
</p>
</PluginDocumentSettingPanel>
);
};
registerPlugin( 'example-restrict-post-types', {
render: RestrictPostTypes,
} );
```
### 将填充内容限定在站点编辑器中显示
若要将填充内容限定在站点编辑器中显示,则需要采用反向逻辑。如果文章类型对象的 `viewable` 属性设置为 `true`,则不应渲染该填充内容。以下示例将在任意站点编辑器界面中渲染其内容。
```js
/**
* WordPress 依赖项
*/
import { registerPlugin } from '@wordpress/plugins';
import {
PluginDocumentSettingPanel,
store as editorStore,
} from '@wordpress/editor';
import { store as coreStore } from '@wordpress/core-data';
import { useSelect } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
/**
* 作为插件组成部分渲染的组件
*/
const SiteEditorDocumentSettingPanel = () => {
// 获取当前文章类型信息
const isViewable = useSelect( ( select ) => {
const postTypeName = select( editorStore ).getCurrentPostType();
const postTypeObject = select( coreStore ).getPostType( postTypeName );
// 可查看的文章类型指能在 WordPress 后台查看的类型,内部类型不会设置为可查看
return postTypeObject?.viewable;
}, [] );
// 若文章类型可查看,则不渲染填充内容
if ( isViewable ) {
return null;
}
return (
<PluginDocumentSettingPanel
name="custom-panel"
title={ __( '站点编辑器示例' ) }
className="custom-panel"
>
<p>{ __( '仅出现在站点编辑器中' ) }</p>
</PluginDocumentSettingPanel>
);
};
registerPlugin( 'example-site-editor', {
render: SiteEditorDocumentSettingPanel,
} );
```
### 将填充内容限定在站点编辑器的特定界面中
此示例在前例基础上,通过提供允许列表来控制填充内容在站点编辑器中的显示界面。
```js
/**
* WordPress 依赖项
*/
import { registerPlugin } from '@wordpress/plugins';
import {
PluginDocumentSettingPanel,
store as editorStore,
} from '@wordpress/editor';
import { store as coreStore } from '@wordpress/core-data';
import { useSelect } from '@wordpress/data';
import { __, sprintf } from '@wordpress/i18n';
/**
* 作为插件组成部分渲染的组件
*/
const SiteEditorDocumentSettingPanel = () => {
// 站点编辑器中的允许区域
const allowedSiteEditorScreens = [
'wp_template', // 模板
'wp_block', // 模式
'wp_template_part', // 模板部件
];
const { isViewable, postType } = useSelect( ( select ) => {
const postTypeName = select( editorStore ).getCurrentPostType();
const postTypeObject = select( coreStore ).getPostType( postTypeName );
return {
// 可查看的文章类型指能在 WordPress 后台查看的类型,内部类型不会设置为可查看
isViewable: postTypeObject?.viewable,
postType: postTypeName,
};
}, [] );
// 若文章类型可查看或不在允许列表中,则不渲染插件
if ( isViewable || ! allowedSiteEditorScreens.includes( postType ) ) {
return null;
}
return (
<PluginDocumentSettingPanel
name="custom-panel"
title={ __( '仅限站点编辑器界面' ) }
className="custom-panel"
>
<p>
{ sprintf(
__(
'仅显示在允许列表中的编辑器界面。%s'
),
allowedSiteEditorScreens.join( '' )
) }
</p>
</PluginDocumentSettingPanel>
);
};
registerPlugin( 'example-site-editor-only', {
render: SiteEditorDocumentSettingPanel,
} );
```
## 运作原理
SlotFill 通过 `createSlotFill` 创建。这会生成 `Slot``Fill` 两个组件,随后用于创建在 `wp.plugins` 全局变量上导出的新组件。
**`PluginPostStatusInfo` SlotFill 的定义**[查看核心代码](https://github.com/WordPress/gutenberg/blob/HEAD/packages/editor/src/components/plugin-post-status-info/index.js#L55)
```js
/**
* 定义摘要面板的可扩展性插槽
*/
/**
* WordPress 依赖项
*/
import { createSlotFill, PanelRow } from '@wordpress/components';
export const { Fill, Slot } = createSlotFill( 'PluginPostStatusInfo' );
const PluginPostStatusInfo = ( { children, className } ) => (
<Fill>
<PanelRow className={ className }>{ children }</PanelRow>
</Fill>
);
PluginPostStatusInfo.Slot = Slot;
export default PluginPostStatusInfo;
```
这个新创建的 Slot 会在编辑器中暴露。以下示例来自核心代码,展示了摘要面板的实现。
可见 `<PluginPostStatusInfo.Slot>` 包裹了面板中所有要显示的项目。任何通过 SlotFill 添加的项目(参见前例)都会包含在 `fills` 参数中,并最终显示在组件末尾。
参见[核心代码](https://github.com/WordPress/gutenberg/tree/HEAD/packages/editor/src/components/sidebar/post-summary.js#L39)。
```js
export default function PostSummary( { onActionPerformed } ) {
const { isRemovedPostStatusPanel } = useSelect( ( select ) => {
// 使用 isEditorPanelRemoved 来在面板被程序化移除时隐藏它
// 不使用 isEditorPanelEnabled 是因为此面板不应通过 UI 禁用
const { isEditorPanelRemoved } = select( editorStore );
return {
isRemovedPostStatusPanel: isEditorPanelRemoved( PANEL_NAME ),
};
}, [] );
return (
<PostPanelSection className="editor-post-summary">
<PluginPostStatusInfo.Slot>
{ ( fills ) => (
<>
<VStack spacing={ 4 }>
<PostCardPanel
onActionPerformed={ onActionPerformed }
/>
<PostFeaturedImagePanel withPanelBody={ false } />
<PostExcerptPanel />
<VStack spacing={ 1 }>
<PostContentInformation />
<PostLastEditedPanel />
</VStack>
{ ! isRemovedPostStatusPanel && (
<VStack spacing={ 2 }>
<VStack spacing={ 1 }>
<PostStatusPanel />
<PostSchedulePanel />
<PostURLPanel />
<PostAuthorPanel />
<PostTemplatePanel />
<PostDiscussionPanel />
<PageAttributesPanel />
<PostSyncStatus />
<BlogTitle />
<PostsPerPage />
<SiteDiscussion />
<PostFormatPanel />
<PostStickyPanel />
</VStack>
<TemplateAreas />
{ fills }
</VStack>
) }
</VStack>
</>
) }
</PluginPostStatusInfo.Slot>
</PostPanelSection>
);
}
```