# 创建动态区块 动态区块是在前端渲染时实时构建结构和内容的区块。 动态区块主要有两个用途: 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),需通过 `` 在 `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 (
{ ! posts && '加载中' } { posts && posts.length === 0 && '暂无文章' } { posts && posts.length > 0 && ( { posts[ 0 ].title.rendered } ) }
); }, } ); ``` 由于是动态区块,无需在客户端重写默认的 `save` 实现,但需要配置服务端组件。前端显示内容取决于 `register_block_type` 的 `render_callback` 属性所调用的函数。 ```php 1, 'post_status' => 'publish', ) ); if ( count( $recent_posts ) === 0 ) { return '暂无文章'; } $post = $recent_posts[ 0 ]; $post_id = $post['ID']; return sprintf( '%2$s', 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 版本引入了 [``](/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 (
); }, } ); ``` 注意此代码使用了 `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))。