Gutenberg区块:如何利用`InnerBlocks`组件构建灵活的内容布局,并实现区块模板锁定?

Gutenberg 区块:利用 InnerBlocks 构建灵活内容布局与区块模板锁定

大家好!今天我们来深入探讨 Gutenberg 区块开发中一个非常重要的组件:InnerBlocksInnerBlocks 允许我们在一个区块中嵌入其他区块,从而构建出复杂且灵活的内容布局。更进一步,我们还可以利用它来实现区块模板锁定,确保用户在特定区块结构中进行内容创作,维护内容的一致性和规范性。

1. InnerBlocks 的基本概念与使用

InnerBlocks 组件本质上是一个容器,它可以容纳其他 Gutenberg 区块。这使得我们可以创建父区块,并通过 InnerBlocks 控制其子区块的类型、数量和排列方式。

最简单的 InnerBlocks 使用方式如下:

const { registerBlockType } = wp.blocks;
const { InnerBlocks } = wp.blockEditor;

registerBlockType( 'my-custom-block/parent-block', {
    title: '父区块',
    icon: 'block-default',
    category: 'common',
    edit: ( props ) => {
        return (
            <div>
                <h2>父区块标题</h2>
                <InnerBlocks />
            </div>
        );
    },
    save: ( props ) => {
        return (
            <div>
                <h2>父区块标题</h2>
                <InnerBlocks.Content />
            </div>
        );
    },
} );

在这个例子中,InnerBlocks 组件被放置在 edit 函数中,允许用户在父区块内部添加任何类型的 Gutenberg 区块。 InnerBlocks.Content 组件则用于 save 函数中,负责渲染父区块中所有子区块的内容。

代码解释:

  • wp.blocks.registerBlockType: 注册一个新的 Gutenberg 区块。
  • wp.blockEditor.InnerBlocks: 引入 InnerBlocks 组件,用于在父区块中嵌套其他区块。
  • edit: 定义区块的编辑界面,用户在这里添加和编辑内容。
  • save: 定义区块的保存方式,决定区块在前端如何呈现。
  • InnerBlocks: 在编辑界面渲染一个可以添加子区块的区域。
  • InnerBlocks.Content: 在前端渲染所有子区块的内容。

2. InnerBlocks 的高级用法:控制子区块类型与数量

仅仅允许添加任何类型的区块可能无法满足我们的需求。我们可能希望限制用户只能添加特定类型的区块,或者控制子区块的数量。InnerBlocks 组件提供了一些属性,可以实现这些功能。

  • allowedBlocks: 指定允许添加到 InnerBlocks 容器中的区块类型数组。
  • template: 定义初始的区块模板,即在父区块创建时,默认包含哪些子区块。
  • templateLock: 锁定区块模板,防止用户修改、添加或删除模板中的区块。

2.1. 限制允许的区块类型 (allowedBlocks)

const { registerBlockType } = wp.blocks;
const { InnerBlocks } = wp.blockEditor;

registerBlockType( 'my-custom-block/restricted-block', {
    title: '受限区块',
    icon: 'block-default',
    category: 'common',
    edit: ( props ) => {
        const ALLOWED_BLOCKS = [ 'core/paragraph', 'core/image' ];

        return (
            <div>
                <h2>受限区块标题</h2>
                <InnerBlocks allowedBlocks={ ALLOWED_BLOCKS } />
            </div>
        );
    },
    save: ( props ) => {
        return (
            <div>
                <h2>受限区块标题</h2>
                <InnerBlocks.Content />
            </div>
        );
    },
} );

在这个例子中,allowedBlocks 属性被设置为 [ 'core/paragraph', 'core/image' ],这意味着用户只能在受限区块内部添加段落和图片区块。

2.2. 定义初始区块模板 (template)

const { registerBlockType } = wp.blocks;
const { InnerBlocks } = wp.blockEditor;

registerBlockType( 'my-custom-block/template-block', {
    title: '模板区块',
    icon: 'block-default',
    category: 'common',
    edit: ( props ) => {
        const TEMPLATE = [
            [ 'core/paragraph', { placeholder: '请输入标题' } ],
            [ 'core/image', {} ],
            [ 'core/paragraph', { placeholder: '请输入内容' } ],
        ];

        return (
            <div>
                <h2>模板区块标题</h2>
                <InnerBlocks template={ TEMPLATE } />
            </div>
        );
    },
    save: ( props ) => {
        return (
            <div>
                <h2>模板区块标题</h2>
                <InnerBlocks.Content />
            </div>
        );
    },
} );

template 属性接受一个二维数组,每个子数组代表一个区块。第一个元素是区块的名称,第二个元素是区块的初始属性。在这个例子中,模板区块创建时会默认包含一个带有 "请输入标题" 占位符的段落区块,一个图片区块,以及一个带有 "请输入内容" 占位符的段落区块。

2.3. 锁定区块模板 (templateLock)

templateLock 属性用于锁定区块模板,防止用户修改、添加或删除模板中的区块。它可以设置为以下两个值:

  • 'all': 锁定所有操作,包括添加、删除和移动区块。
  • 'insert': 只允许移动和编辑现有区块,禁止添加或删除区块。
const { registerBlockType } = wp.blocks;
const { InnerBlocks } = wp.blockEditor;

registerBlockType( 'my-custom-block/locked-block', {
    title: '锁定区块',
    icon: 'block-default',
    category: 'common',
    edit: ( props ) => {
        const TEMPLATE = [
            [ 'core/paragraph', { placeholder: '请输入标题' } ],
            [ 'core/image', {} ],
            [ 'core/paragraph', { placeholder: '请输入内容' } ],
        ];

        return (
            <div>
                <h2>锁定区块标题</h2>
                <InnerBlocks template={ TEMPLATE } templateLock="all" />
            </div>
        );
    },
    save: ( props ) => {
        return (
            <div>
                <h2>锁定区块标题</h2>
                <InnerBlocks.Content />
            </div>
        );
    },
} );

在这个例子中,templateLock 属性被设置为 'all',这意味着用户无法修改、添加或删除模板区块中的任何内容。他们只能编辑现有区块的内容。

属性 描述 可选值
allowedBlocks 定义允许添加到 InnerBlocks 容器中的区块类型数组。 区块名称数组
template 定义初始的区块模板,即在父区块创建时,默认包含哪些子区块。 二维数组
templateLock 锁定区块模板,防止用户修改、添加或删除模板中的区块。 'all', 'insert', false

3. 构建复杂布局:案例分析

现在,让我们通过一个具体的案例来演示如何使用 InnerBlocks 构建一个复杂的内容布局。假设我们需要创建一个“三栏布局”区块,允许用户在三个栏目中分别添加内容。

const { registerBlockType } = wp.blocks;
const { InnerBlocks } = wp.blockEditor;
const { useBlockProps } = wp.blockEditor;

registerBlockType( 'my-custom-block/three-column-layout', {
    title: '三栏布局',
    icon: 'columns',
    category: 'layout',
    attributes: {
        columns: {
            type: 'number',
            default: 3
        }
    },
    edit: ( props ) => {
        const { clientId } = props;
        const blockProps = useBlockProps();
        const TEMPLATE = [
            [ 'core/column', { width: 33.33 }, [ [ 'core/paragraph', { placeholder: '第一栏内容' } ] ] ],
            [ 'core/column', { width: 33.33 }, [ [ 'core/paragraph', { placeholder: '第二栏内容' } ] ] ],
            [ 'core/column', { width: 33.33 }, [ [ 'core/paragraph', { placeholder: '第三栏内容' } ] ] ],
        ];

        return (
            <div { ...blockProps }>
                <h2>三栏布局</h2>
                <div className="three-column-layout">
                    <InnerBlocks
                        template={ TEMPLATE }
                        templateLock="all"
                        allowedBlocks={['core/paragraph', 'core/image', 'core/list']}
                    />
                </div>
            </div>
        );
    },
    save: ( props ) => {
        const blockProps = useBlockProps.save();
        return (
            <div { ...blockProps }>
                <div className="three-column-layout">
                    <InnerBlocks.Content />
                </div>
            </div>
        );
    },
} );

代码解释:

  • attributes: 定义区块的属性,这里定义了一个 columns 属性,用于控制栏目的数量,默认为 3。
  • useBlockProps 获取标准的区块 props, 保证区块样式正确。
  • TEMPLATE: 定义初始的区块模板,包含三个 core/column 区块,每个区块都包含一个默认的段落区块。
  • templateLock="all": 锁定区块模板,防止用户修改栏目的数量和结构。
  • allowedBlocks: 限制栏目里允许添加的区块类型。
  • className="three-column-layout": 为父区块添加一个 CSS 类,方便我们自定义样式。

CSS 样式 (three-column-layout.css):

.three-column-layout {
    display: flex;
    flex-wrap: wrap;
}

.wp-block-core-column {
    flex: 1;
    padding: 10px;
    box-sizing: border-box; /* 确保 padding 不会增加元素宽度 */
}

注意: 你需要在你的主题或插件中注册并加载这个 CSS 文件。

实现效果:

这个区块创建后,会默认包含三个栏目,每个栏目中都有一个段落区块。用户可以在每个栏目中添加段落、图片或列表,但无法添加或删除栏目,也无法改变栏目的排列方式。

扩展:

你可以根据自己的需求,修改 TEMPLATEallowedBlocks 属性,以及 CSS 样式,来创建各种各样的复杂布局。例如,你可以添加一个属性来控制栏目的比例,或者允许用户在栏目中添加自定义的区块。

4. 动态渲染:更高级的布局控制

虽然 InnerBlockstemplate 属性可以定义初始的区块模板,但在某些情况下,我们可能需要更动态地控制子区块的渲染。例如,我们可能需要根据父区块的属性值,动态地调整子区块的类型和数量。

在这种情况下,我们可以使用 JavaScript 来动态地生成 InnerBlocks 的内容。

const { registerBlockType } = wp.blocks;
const { InnerBlocks, InspectorControls } = wp.blockEditor;
const { PanelBody, RangeControl } = wp.components;

registerBlockType( 'my-custom-block/dynamic-layout', {
    title: '动态布局',
    icon: 'columns',
    category: 'layout',
    attributes: {
        columns: {
            type: 'number',
            default: 2,
        },
    },
    edit: ( props ) => {
        const { attributes, setAttributes } = props;
        const { columns } = attributes;

        const onChangeColumns = ( newColumns ) => {
            setAttributes( { columns: newColumns } );
        };

        const TEMPLATE = Array( columns ).fill( [ 'core/paragraph', { placeholder: '请输入内容' } ] );

        return (
            <div>
                <InspectorControls>
                    <PanelBody title="布局设置">
                        <RangeControl
                            label="栏目数量"
                            value={ columns }
                            onChange={ onChangeColumns }
                            min={ 1 }
                            max={ 6 }
                        />
                    </PanelBody>
                </InspectorControls>
                <h2>动态布局</h2>
                <div className="dynamic-layout" style={{ display: 'flex' }}>
                    <InnerBlocks template={ TEMPLATE } allowedBlocks={['core/paragraph']} />
                </div>
            </div>
        );
    },
    save: ( props ) => {
        return (
            <div className="dynamic-layout" style={{ display: 'flex' }}>
                <InnerBlocks.Content />
            </div>
        );
    },
} );

代码解释:

  • attributes.columns: 定义一个 columns 属性,用于控制栏目的数量。
  • InspectorControls: 添加一个 InspectorControls 组件,允许用户在侧边栏中调整栏目的数量。
  • RangeControl: 添加一个 RangeControl 组件,用于控制栏目的数量,范围从 1 到 6。
  • TEMPLATE: 使用 Array( columns ).fill() 方法动态生成区块模板,根据 columns 属性的值,创建相应数量的段落区块。
  • style={{ display: 'flex' }}: 使用内联样式,确保布局呈现为 flex 容器。

实现效果:

这个区块创建后,用户可以在侧边栏中调整栏目的数量。根据栏目的数量,区块内部会自动创建相应数量的段落区块。

优点:

  • 更灵活的布局控制,可以根据父区块的属性值动态地调整子区块的类型和数量。
  • 更好的用户体验,用户可以通过侧边栏轻松地调整布局。

5. 最佳实践与注意事项

  • 合理使用 allowedBlocks: 限制允许的区块类型可以提高内容的一致性和规范性,但也可能限制用户的创作自由。因此,需要根据实际需求,权衡利弊。
  • 谨慎使用 templateLock: 锁定区块模板可以确保内容的结构和布局符合预期,但也可能限制用户的修改和定制。因此,需要谨慎使用 templateLock,确保用户仍然有一定的创作空间。
  • 注意性能: 在包含大量子区块的父区块中,InnerBlocks 可能会影响编辑器的性能。因此,需要尽量优化代码,避免不必要的渲染。
  • 考虑响应式设计: 在使用 InnerBlocks 构建复杂布局时,需要考虑响应式设计,确保在不同设备上都能正确显示。你可以使用 CSS 媒体查询来调整布局。
  • 测试: 在发布区块之前,务必进行充分的测试,确保在各种情况下都能正常工作。

6. InnerBlocks 的替代方案:Block Variations

在某些场景下,如果只是为了提供预设的区块配置,可以考虑使用 Block Variations。Block Variations 允许你创建同一区块的不同变体,每种变体都有不同的属性和预设值。这可以简化区块的开发,并提高用户体验。但是 Block Variations 并不提供像 InnerBlocks 那样灵活的嵌套和布局控制能力。需要根据具体需求选择合适的方案。

7. 总结

InnerBlocks 是 Gutenberg 区块开发中一个强大的工具,它可以帮助我们构建复杂且灵活的内容布局。通过合理使用 allowedBlockstemplatetemplateLock 属性,我们可以更好地控制子区块的类型、数量和排列方式,从而提高内容的一致性和规范性。

掌握 InnerBlocks 的使用,可以提升 Gutenberg 区块开发的效率和质量,为用户提供更好的内容创作体验。

掌握 InnerBlocks 组件及其属性,可以灵活地构建内容布局,并使用 templateLock 属性来锁定模板,保证内容结构的一致性。

使用 InnerBlocks 组件,可以更好地控制 Gutenberg 区块的嵌套和布局,实现更复杂、更灵活的内容管理。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注