137 lines
5.7 KiB
Markdown
137 lines
5.7 KiB
Markdown
|
|
# 创建动态区块
|
|||
|
|
|
|||
|
|
动态区块是在前端渲染时实时构建结构和内容的区块。
|
|||
|
|
|
|||
|
|
动态区块主要有两个用途:
|
|||
|
|
|
|||
|
|
1. **内容需要实时更新的区块**:即使文章未更新,区块内容也会自动变化。WordPress 自带的「最新文章」区块就是典型示例——每当发布新文章时,所有使用该区块的位置都会同步更新。
|
|||
|
|
2. **需要即时呈现代码更新的区块**:当修改区块代码(HTML/CSS/JS)时,使用动态区块可确保修改立即在全站所有该区块实例上生效。(若不使用动态区块,Gutenberg 的[验证流程](/docs/reference-guides/block-api/block-edit-save.md#validation)会触发,导致用户看到“此区块似乎已被外部修改”的提示)
|
|||
|
|
|
|||
|
|
对于多数动态区块,`save` 回调函数应返回 `null`,这会让编辑器仅将[区块属性](/docs/reference-guides/block-api/block-attributes.md)保存至数据库。这些属性随后会传入服务端渲染回调,从而由开发者决定如何在前端展示区块。返回 `null` 时,编辑器会跳过区块标记验证流程,避免因频繁变化的标记引发问题。
|
|||
|
|
|
|||
|
|
若在动态区块中使用 [InnerBlocks](/docs/how-to-guides/block-tutorial/nested-blocks-inner-blocks.md),需通过 `<InnerBlocks.Content/>` 在 `save` 回调中保存内部区块内容。
|
|||
|
|
|
|||
|
|
也可保存区块的 HTML 表示形式。若设置了服务端渲染回调,该 HTML 会被回调输出替换;但当区块被停用或渲染回调被移除时,此 HTML 仍会正常渲染。
|
|||
|
|
|
|||
|
|
区块属性可用于保存任何需要存储的内容或设置。例如最新文章区块中,可将要显示的文章数量保存为属性;又或者针对需要在前端展示的每项内容(如标题文本、段落文字、图片、链接等),都可通过属性进行配置。
|
|||
|
|
|
|||
|
|
以下代码示例展示了如何创建仅显示最新文章链接的动态区块:
|
|||
|
|
|
|||
|
|
```jsx
|
|||
|
|
import { registerBlockType } from '@wordpress/blocks';
|
|||
|
|
import { useSelect } from '@wordpress/data';
|
|||
|
|
import { useBlockProps } from '@wordpress/block-editor';
|
|||
|
|
|
|||
|
|
registerBlockType( 'gutenberg-examples/example-dynamic', {
|
|||
|
|
apiVersion: 3,
|
|||
|
|
title: '示例:最新文章',
|
|||
|
|
icon: 'megaphone',
|
|||
|
|
category: 'widgets',
|
|||
|
|
|
|||
|
|
edit: () => {
|
|||
|
|
const blockProps = useBlockProps();
|
|||
|
|
const posts = useSelect( ( select ) => {
|
|||
|
|
return select( 'core' ).getEntityRecords( 'postType', 'post' );
|
|||
|
|
}, [] );
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<div { ...blockProps }>
|
|||
|
|
{ ! posts && '加载中' }
|
|||
|
|
{ posts && posts.length === 0 && '暂无文章' }
|
|||
|
|
{ posts && posts.length > 0 && (
|
|||
|
|
<a href={ posts[ 0 ].link }>
|
|||
|
|
{ posts[ 0 ].title.rendered }
|
|||
|
|
</a>
|
|||
|
|
) }
|
|||
|
|
</div>
|
|||
|
|
);
|
|||
|
|
},
|
|||
|
|
} );
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
由于是动态区块,无需在客户端重写默认的 `save` 实现,但需要配置服务端组件。前端显示内容取决于 `register_block_type` 的 `render_callback` 属性所调用的函数。
|
|||
|
|
|
|||
|
|
```php
|
|||
|
|
<?php
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 插件名称:Gutenberg 动态区块示例
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
function gutenberg_examples_dynamic_render_callback( $block_attributes, $content ) {
|
|||
|
|
$recent_posts = wp_get_recent_posts( array(
|
|||
|
|
'numberposts' => 1,
|
|||
|
|
'post_status' => 'publish',
|
|||
|
|
) );
|
|||
|
|
if ( count( $recent_posts ) === 0 ) {
|
|||
|
|
return '暂无文章';
|
|||
|
|
}
|
|||
|
|
$post = $recent_posts[ 0 ];
|
|||
|
|
$post_id = $post['ID'];
|
|||
|
|
return sprintf(
|
|||
|
|
'<a class="wp-block-my-plugin-latest-post" href="%1$s">%2$s</a>',
|
|||
|
|
esc_url( get_permalink( $post_id ) ),
|
|||
|
|
esc_html( get_the_title( $post_id ) )
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function gutenberg_examples_dynamic() {
|
|||
|
|
// 自动加载依赖项与版本号
|
|||
|
|
$asset_file = include( plugin_dir_path( __FILE__ ) . 'build/index.asset.php');
|
|||
|
|
|
|||
|
|
wp_register_script(
|
|||
|
|
'gutenberg-examples-dynamic',
|
|||
|
|
plugins_url( 'build/block.js', __FILE__ ),
|
|||
|
|
$asset_file['dependencies'],
|
|||
|
|
$asset_file['version']
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
register_block_type( 'gutenberg-examples/example-dynamic', array(
|
|||
|
|
'api_version' => 3,
|
|||
|
|
'editor_script' => 'gutenberg-examples-dynamic',
|
|||
|
|
'render_callback' => 'gutenberg_examples_dynamic_render_callback'
|
|||
|
|
) );
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
add_action( 'init', 'gutenberg_examples_dynamic' );
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
需要注意以下几点:
|
|||
|
|
- `edit` 函数仍在编辑器中展示区块预览(可与渲染版本完全不同,由区块作者决定)
|
|||
|
|
- 内置 `save` 函数直接返回 `null`,因为渲染在服务端完成
|
|||
|
|
- 服务端渲染函数接收区块属性及内部内容作为参数,返回标记(与短代码机制高度相似)
|
|||
|
|
|
|||
|
|
**注意:** 关于颜色、边框、间距等常见自定义设置,我们将在[下一章](/docs/how-to-guides/block-tutorial/block-supports-in-dynamic-blocks.md)了解如何通过区块支持功能高效实现。
|
|||
|
|
|
|||
|
|
## 在区块编辑器中实时渲染
|
|||
|
|
|
|||
|
|
Gutenberg 2.8 版本引入了 [`<ServerSideRender>`](/packages/server-side-render/README.md) 区块,支持在服务端使用 PHP 进行渲染而非 JavaScript。
|
|||
|
|
|
|||
|
|
*服务端渲染仅作为降级方案,始终推荐使用客户端 JavaScript 渲染(速度更快且支持更灵活的编辑器操作)。*
|
|||
|
|
|
|||
|
|
```jsx
|
|||
|
|
import { registerBlockType } from '@wordpress/blocks';
|
|||
|
|
import ServerSideRender from '@wordpress/server-side-render';
|
|||
|
|
import { useBlockProps } from '@wordpress/block-editor';
|
|||
|
|
|
|||
|
|
registerBlockType( 'gutenberg-examples/example-dynamic', {
|
|||
|
|
apiVersion: 3,
|
|||
|
|
title: '示例:最新文章',
|
|||
|
|
icon: 'megaphone',
|
|||
|
|
category: 'widgets',
|
|||
|
|
|
|||
|
|
edit: function ( props ) {
|
|||
|
|
const blockProps = useBlockProps();
|
|||
|
|
return (
|
|||
|
|
<div { ...blockProps }>
|
|||
|
|
<ServerSideRender
|
|||
|
|
block="gutenberg-examples/example-dynamic"
|
|||
|
|
attributes={ props.attributes }
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
);
|
|||
|
|
},
|
|||
|
|
} );
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
注意此代码使用了 `wp-server-side-render` 包但未使用 `wp-data`,请确保在 PHP 代码中更新依赖项。建议使用 wp-scripts 自动构建依赖(具体 PHP 代码配置可参考 [block-development-examples 代码库](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/basic-esnext-a2ab62))。
|