如何从BlockVariationPicker中选择块变体

时间:2021-06-16 作者:Elizabeth

我有一个具有块变体的自定义块。如果我确定了变更的范围”;插入器“;,它们按预期工作。但如果我让范围;“块”;并使用BlockVariationPicker,以便用户在添加块时选择一个变体(就像他们在添加核心列块时所做的那样),当我单击变体图标时,什么都不会发生。

我想这是因为我需要添加onSelect,但我不知道该怎么办。

寄存器块:

import { __ } from "@wordpress/i18n";

import { registerBlockType } from "@wordpress/blocks";

import "./style.scss";

import Edit from "./edit";
import save from "./save";

registerBlockType("create-block/variation", {
    edit: Edit,
    save,
});
我的变体:

const variations = [
{
    name: "one-column",
    title: __("One Column"),
    description: __("One column"),
    icon: "palmtree",
    innerBlocks: [["core/paragraph"]],
    scope: ["inserter"],
},
{
    name: "two-columns",
    title: __("Two Column"),
    description: __("Two columns"),
    icon: "palmtree",
    // isDefault: true,
    innerBlocks: [["core/paragraph"], ["core/paragraph"]],
    scope: ["inserter"],
},
];

export default variations;
我的编辑。js公司

import { __ } from "@wordpress/i18n";

import {
    useBlockProps,
    __experimentalBlockVariationPicker as BlockVariationPicker,
} from "@wordpress/block-editor";

import variations from "./variations";

import "./editor.scss";

export default function Edit() {
    return (
        <div {...useBlockProps()}>
            <BlockVariationPicker
                variations={variations}
                label={__("Menu Columns")}
                instructions={__("Choose how many menu columns")}
            />
        </div>
    );
}
当用户单击在编辑器中输入的变体时,我需要添加什么才能做到这一点?这是我添加块时的样子,但单击时什么也没有发生。enter image description here

2 个回复
最合适的回答,由SO网友:Sally CJ 整理而成

我想这是因为我需要添加onSelect,但我不确定该怎么办。

当用户单击在编辑器中输入的变体时,我需要添加什么才能做到这一点?

一种方法是添加variation 属性设置为块类型,然后在onSelect 变量选择器的回调。这反过来将指示React重新渲染块(因为块状态已更改),因此在该渲染上,我们不再显示变体选择器。因此,基本上,选择器是;已关闭:)

请参见下面的示例,其中块类型渲染简单button 有两种变体-带图标和不带图标。

// File: index.js

import { registerBlockType } from \'@wordpress/blocks\';
import {
    useBlockProps,
    __experimentalBlockVariationPicker as BlockVariationPicker,
} from \'@wordpress/block-editor\';
import { Button } from \'@wordpress/components\';

const variations = [{
    name: \'button-with-icon\',
    title: \'Button + Text + Icon\',
    icon: \'button\',
    scope: [ \'block\' ],
    attributes: { icon: \'heart\' },
}, {
    name: \'button-without-icon\',
    title: \'Button + Text only\',
    icon: \'button\',
    scope: [ \'block\' ],
}];

registerBlockType( \'my-blocks/foo-button\', {
    apiVersion: 2,
    title: \'Foo Button\',
    category: \'formatting\',
    attributes: {
        icon: {
            type: \'string\',
            default: \'\',
        },
        variation: {
            type: \'string\',
            default: \'\',
        },
    },
    edit( { attributes, setAttributes } ) {
        if ( ! attributes.variation ) {
            return (
                <div { ...useBlockProps() }>
                    <BlockVariationPicker
                        variations={ variations }
                        label="Button Variant"
                        onSelect={ ( variation = variations[0] ) => {
                            setAttributes( {
                                ...variation.attributes,
                                variation: variation.name,
                            });
                        }}
                    />
                </div>
            );
        }

        return (
            <div { ...useBlockProps() }>
                <Button
                    text="Foo Button"
                    icon={ attributes.icon }
                />
            </div>
        );
    },
    save: ( { attributes } ) => (
        <div { ...useBlockProps.save() }>
            <Button
                text="Foo Button"
                icon={ attributes.icon }
            />
        </div>
    ),
} );
然而,在inner blocks, 您可能希望使用与核心列块相同的方法(see source on GitHub), 检查当前块是否包含任何内部块,如果是,则显示内部块;否则,将显示变体选择器。

这里有一个完整的工作示例,你可以尝试我在你的variations.js 文件:

// File: index.js

import {
    registerBlockType,
    createBlocksFromInnerBlocksTemplate,
} from \'@wordpress/blocks\';
import {
    useBlockProps,
    __experimentalUseInnerBlocksProps as useInnerBlocksProps,
    store as blockEditorStore,
    __experimentalBlockVariationPicker as BlockVariationPicker,
    InnerBlocks,
} from \'@wordpress/block-editor\';
import { useDispatch, useSelect } from \'@wordpress/data\';

import variations from \'./variations\';

// Note that you can do EditContainer( props ) or EditContainer( { attributes, etc } ).
function EditContainer() {
    const blockProps = useBlockProps();
    const innerBlocksProps = useInnerBlocksProps( blockProps, {
        //allowedBlocks: ALLOWED_BLOCKS,
        orientation: \'horizontal\',
        renderAppender: false,
    } );

    return <div { ...innerBlocksProps } />;
}

function Placeholder( { clientId, setAttributes } ) {
    // Always set a default variation, particularly if allowing skipping the variation picker.
    const defaultVariation = variations[0];
    // Or do something like this, which selects the variation having "isDefault: true":
//  const defaultVariation = variations.filter( item => item.isDefault )[0] || variations[0];

    const { replaceInnerBlocks } = useDispatch( blockEditorStore );
    const blockProps = useBlockProps();

    return (
        <div { ...blockProps }>
            <BlockVariationPicker
                label="Section Variant"
                variations={ variations }
                onSelect={ ( variation = defaultVariation ) => {
                    if ( variation.attributes ) {
                        setAttributes( variation.attributes );
                    }
                    if ( variation.innerBlocks ) {
                        replaceInnerBlocks(
                            clientId,
                            createBlocksFromInnerBlocksTemplate(
                                variation.innerBlocks
                            ),
                            true
                        );
                    }
                } }
                allowSkip
            />
        </div>
    );
}

const Edit = ( props ) => {
    const { clientId } = props;
    const hasInnerBlocks = useSelect(
        ( select ) =>
            select( blockEditorStore ).getBlocks( clientId ).length > 0,
        [ clientId ]
    );
    const Component = hasInnerBlocks
        ? EditContainer // display the inner blocks
        : Placeholder;  // or the variation picker

    return <Component { ...props } />;
};

registerBlockType( \'my-blocks/foo-section\', {
    apiVersion: 2,
    title: \'Foo Section\',
    category: \'layout\',
    edit: Edit,
    save: () => (
        <div { ...useBlockProps.save( { className: \'foo-section\' } ) }>
            <InnerBlocks.Content />
        </div>
    ),
} );
因此,请尝试一下,如果您对代码有任何疑问,请告诉我。:)

SO网友:Sally CJ

*这是对公认答案的补充答案,所以要进行手术,请按照医生的处方将其作为主要答案的补充维生素……:p

因此,作为对您评论的回复:

是否可以在其中添加其他元素?我有RichTextand InspectorControl。据我所知return <div { ...innerBlocksProps } />; 无法添加任何内容。

是的,有可能:

首先,定义我们的进口:

import {
    useBlockProps,
    __experimentalUseInnerBlocksProps as useInnerBlocksProps,
    store as blockEditorStore,
    __experimentalBlockVariationPicker as BlockVariationPicker,
    InnerBlocks,
    // add these lines:
    InspectorControls,
    RichText,
} from \'@wordpress/block-editor\';
// and also this:
import { PanelBody, TextControl } from \'@wordpress/components\';
EditContainer() 函数,使其包括InspectorControlsRichText 元素-inspector控件(在下面的代码中,它只有一个简单的文本框)将显示在侧栏中,而富文本将放置在内部块的上方(通过特定变体定义):

function EditContainer() {
    const blockProps = useBlockProps();
    const innerBlocksProps = useInnerBlocksProps( {}, {
        //allowedBlocks: ALLOWED_BLOCKS,
        orientation: \'horizontal\',
        renderAppender: false,
    } );

    // *This line is just for demonstration, and so does the onChange callback below.
    // In actual implementation, you\'d want to set the data via the block attributes.
    const [ foo, setFoo ] = wp.element.useState( \'bar baz\' );

    return (
        <div { ...blockProps }>
            <InspectorControls>
                <PanelBody>
                    <TextControl
                        label="Foo Input"
                        value={ foo }
                        onChange={ ( value ) => setFoo( value ) }
                    />
                </PanelBody>
            </InspectorControls>

            <RichText
                value={ foo }
                onChange={ ( value ) => setFoo( value ) }
            />

            <div { ...innerBlocksProps } />
        </div>
    );
}
因此,您需要知道的主要内容是,我使用div包装检查器控件、富文本以及内部块。因此,我使用blockProps 使用该div和notuseInnerBlocksProps.

中的save 函数,但如何输出富文本和输入值(即上面的“Foo input”值)将取决于您。

如果一切顺利,你会看到这样的情况:

Sample preview in the editor - when editing the Foo Input

Sample preview in the editor - when editing an inner block

相关推荐