Gutenberg - 一种块类型中的多个 InnerBlocks

Gutenberg - Multiple InnerBlocks in one block-type

我正在尝试阻止自定义列,因为 gutenberg 使用的 wordpress 默认值不是我需要的。

所以我查看了它是如何工作的,它使用带有布局定义的 InnerBlocks 块,但是无法为列指定 html 标签和 class,所以它没用为了我。

然后我决定使用 map 循环出列,效果很好,然后我在每一列中添加了 InnerBlocks 组件以允许将其他块插入到列中,但问题是在每一列中 InnerBlocks 的内容是共享的,所以我尝试为每个 InnerBlock 和列设置键 属性 是唯一的,并且它们的内容仍然是共享的(不,我没有使用共享块)。

看起来古腾堡在每一列中都使用了相同的 InnerBlocks 实例。

我正在尝试构建一个块类型,您可以在其中动态添加列并在每列中添加 "cards" 和一些信息。

为了让大家知道我在做什么,这里是编辑功能的 return:

<section className="infonav">
            <div className="infonav__container">
                <div>
                    <button onClick={onAddBox}>{__('Add column', 'zmg-blocks')}</button>
                </div>
                <div className="infonav__row">
                    {[...new Array(columns).keys()].map((item, index) => {
                        return (
                                <div className="infonav__row__col" key={"info_cols"+index}>
                                    <div>
                                        <button onClick={onRemoveBox.bind(index)}>
                                            {__('Remove', 'zmg-blocks')}
                                        </button>
                                    </div>
                                    <InnerBlocks key={"info_boxes"+index}/>
                                </div>
                        );
                    })}
                </div>
            </div>
        </section>

谢谢

似乎gutenberg Innerblocks 只能在一个块中使用一次

Note: A block can render at most a single InnerBlocks and InnerBlocks.Content element in edit and save respectively. To create distinct arrangements of nested blocks, create a separate block type which renders its own InnerBlocks and assign as the sole allowedBlocks type.

Source: https://github.com/WordPress/gutenberg/tree/master/packages/block-editor/src/components/inner-blocks

您需要创建另一个自定义块(仅用于列)以及此块,该块也在其中使用 Innerblock,以便其他块可以嵌套在其中。 您可以使用 allowedBlocks 仅允许此块中的自定义列

如果您打算从 'block-editor' 通过 InnerBlock 添加多个古腾堡块,如下所示,目前还无法添加多个块:

const BLOCK_TEMPLATE = [
  ['image-slider', { width: 800, height: 400 }],
  ['menu'],
];

registerBlockType('peregrine/inner-block-demo', {

  title: 'Inner Block Demo',

  edit({ className }) {
    return (
      <div className={className}>
        <InnerBlocks
          template={BLOCK_TEMPLATE}
          templateLock="all"
        />
      </div>
    );
  },

  save() {
    return (
      <div>
        <InnerBlocks.Content />
      </div>
    );
  },
});

Multiple inner blocks have complexities that don't seem worth the effort, and in general it either hints at a block that should be broken down into multiple simpler blocks, or with block attributes (not children). Let us know how the above suggestion work for you and we could revisit.

你可以关注这里的讨论:https://github.com/WordPress/gutenberg/issues/6808

但是,您的代码看起来更像是添加内部元素,这是可能的。

因此,为了进一步澄清,您提供给 registerBlockType 函数的不是块。古腾堡块优雅的简码,像这样:

<!-- wp:image -->
<figure class="wp-block-image"><img src="source.jpg" alt="" /></figure>
<!-- /wp:image -->

或者这个:

<!-- wp:latest-posts {"postsToShow":4,"displayPostDate":true} /-->

第一个称为静态块,因为它包含其内容。第二个称为动态块,因为它是自关闭块并且没有内容。内容将从您注册块时提供的 php 回调中检索。

Gutenberg 使用 React 将块的可视化表示打印到编辑器屏幕上。设置对象上的编辑方法应该 return 一个反应元素,这个元素将用于在编辑器中为块生成视觉表示。 save 方法也应该 return 反应元素,但是这个元素将被呈现为静态 html 并保存到数据库中:<figure class="wp-block-image"><img src="source.jpg" alt="" /></figure>。现在,动态块没有 return 元素,因为它们 return 为空,所以它们中没有内容,这就是它们自动关闭的原因。

当服务器响应请求时,它会获取存储在数据库中的内容并通过解析器运行它来查看它是静态块还是动态块。如果块是静态的,它本身就有内容,因此内容将被 returned。如果它是动态的,注册的回调函数将被调用并且它的 return 值将被 returned.

现在,为了回答您的问题,保存和编辑功能应该 return React 元素。反应元素必须有单个根元素,但内部元素可以是任何常规 html 像这样的元素:

<div>
  <h1>Hello world</h1>
  <p>This is a sentence</p>
</div>

这是出于性能原因。 DOM 操作很昂贵,这就是为什么它在 DOM 中只有一个入口点。这就是为什么它非常快。它有自己的 DOM 然后,一整棵树驻留在内存中。当发生更改时,React 将遍历其 DOM 树并仅渲染更改的分支,不会为每个小更改绘制整棵树。

这里的重要细节是上面的代码看起来像 html 但它不是,它是 jsx。 React 无法直接渲染 html。 jsx会被babel之类的转译器转译成react元素

React也有createElement方法可以用来创建react元素。 wp 重新导出这个方法。

您可以在一个反应​​元素中渲染另一个反应元素。如果不学习 React,您将永远无法完全掌握块的力量或潜力。 React 库没有那么大。一旦你掌握了它背后的理念,你就可以在一两周内学会足够的东西来提高工作效率。

我遇到了同样的问题,基于 创建了如下内容:

父块:

registerBlockType("my-plugin/parent-block", {

    title: "Parent block",

    // Amount of columns
    attributes: {
        columns: { type: "number", default: 3 },
    }

    edit(props) {
        const { attributes: { columns } } = props;

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

        // Either go for the template route
        // (create an inner block template based on amount of columns)
        const template = Array.from(Array(columns).keys()).map((i) => [
            "my-plugin/custom-inner-block",
        ]);
      
        // Or go for the allowed blocks route
        const allowedBlocks = ["my-plugin/custom-inner-block"];

        return (
            <div {...useBlockProps()}>

                {/* Use RangeControl in the InspectorControls to 
                    control the number of columns. */}
                <InspectorControls key="setting">
                    <div class="block-editor-block-card">
                        <fieldset>
                            <legend className="blocks-base-control__label">
                                {__("Amount of columns", "gutenpride")}
                            </legend>
                            <RangeControl
                                label="Columns"
                                value={columns}
                                onChange={(value) => onChangeColumns(value)}
                                min={1}
                                max={3}
                            />
                        </fieldset>
                    </div>
                </InspectorControls>
    
                <InnerBlocks
                    template={activeTemplate}
                    templateLock="all"
                    allowedBlocks={allowedBlocks}
                />
            </div>
        )
    },

    save() {
        return (
            <div {...useBlockProps.save()}>
                <InnerBlocks.Content />
            </div>
        );
    },

    // ...
}

自定义内部块:

registerBlockType("my-plugin/custom-inner-block", {

    title: "Custom Inner Block",

    edit(props) {
        const { attributes } = props;
        const { title } = attributes;

        return (
            <div {...useBlockProps()}>
                <InnerBlocks/>
            </div>
        );
    },

    save() {
        return (
            <div {...useBlockProps.save()}>
                <InnerBlocks.Content />
            </div>
        );
    },

    // ...
});