Gutenberg 区块:利用 InnerBlocks 构建灵活内容布局与区块模板锁定
大家好!今天我们来深入探讨 Gutenberg 区块开发中一个非常重要的组件:InnerBlocks
。InnerBlocks
允许我们在一个区块中嵌入其他区块,从而构建出复杂且灵活的内容布局。更进一步,我们还可以利用它来实现区块模板锁定,确保用户在特定区块结构中进行内容创作,维护内容的一致性和规范性。
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 文件。
实现效果:
这个区块创建后,会默认包含三个栏目,每个栏目中都有一个段落区块。用户可以在每个栏目中添加段落、图片或列表,但无法添加或删除栏目,也无法改变栏目的排列方式。
扩展:
你可以根据自己的需求,修改 TEMPLATE
和 allowedBlocks
属性,以及 CSS 样式,来创建各种各样的复杂布局。例如,你可以添加一个属性来控制栏目的比例,或者允许用户在栏目中添加自定义的区块。
4. 动态渲染:更高级的布局控制
虽然 InnerBlocks
的 template
属性可以定义初始的区块模板,但在某些情况下,我们可能需要更动态地控制子区块的渲染。例如,我们可能需要根据父区块的属性值,动态地调整子区块的类型和数量。
在这种情况下,我们可以使用 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 区块开发中一个强大的工具,它可以帮助我们构建复杂且灵活的内容布局。通过合理使用 allowedBlocks
、template
和 templateLock
属性,我们可以更好地控制子区块的类型、数量和排列方式,从而提高内容的一致性和规范性。
掌握 InnerBlocks
的使用,可以提升 Gutenberg 区块开发的效率和质量,为用户提供更好的内容创作体验。
掌握 InnerBlocks
组件及其属性,可以灵活地构建内容布局,并使用 templateLock
属性来锁定模板,保证内容结构的一致性。
使用 InnerBlocks
组件,可以更好地控制 Gutenberg 区块的嵌套和布局,实现更复杂、更灵活的内容管理。