You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从Gutenberg子块更新父块属性?

问题:为Gutenberg Tab子块添加图标并同步到父块属性

我克隆了一款基础Tab块插件,现在要给每个Tab子块添加选择图标的功能。目前已经能通过MediaUpload组件选择文件,且能在activeTab对象中看到选中的文件,但无法更新父块的属性,导致在父块中引用icon_url时该属性不存在。

当前代码情况

tab/edit.js 代码

const Edit = ({ attributes, setAttributes, clientId }) => {
    const { uid, activeTab } = attributes;

    useEffect(() => {
        if (!uid) {
            setAttributes({ uid: clientId });
        }
    }, []);

    const display = activeTab === uid ? "block" : "none";
    const ALLOWED_MEDIA_TYPES = ["image", "svg"];

    const setTabIcon = (icon_url) => {
        const parentBlock = select("core/block-editor").getBlock(clientId);
        dispatch("core/block-editor").updateBlockAttributes(
            parentBlock.clientId,
            {
                ...attributes,
                icon_url,
            }
        );
    };

    return (
        <div {...useBlockProps()}>
            <InspectorControls>
                <div>
                    <MediaUpload
                        allowedTypes={ALLOWED_MEDIA_TYPES}
                        onSelect={(media) => setTabIcon(media.url)}
                        render={({ open }) => (
                            <button onClick={open}>Open Media Library</button>
                        )}
                    />
                </div>
            </InspectorControls>
            <div className="guten-tab-panel" style={{ display }}>
                <InnerBlocks
                    allowedBlocks={["core/heading", "core/paragraph"]}
                    renderAppender={() => <InnerBlocks.ButtonBlockAppender />}
                />
            </div>
        </div>
    );
};

export default Edit;

tabs/tabs.js 代码

const Edit = ({ attributes, setAttributes, clientId }) => {
    const { tabs, activeTab } = attributes;

    const blockProps = useBlockProps({
        className: `${useBlockProps().className} guten-tab-wrapper`,
    });

    const setActiveTab = (uid) => {
        setAttributes({ activeTab: uid });
        const parentBlock = select("core/block-editor").getBlock(clientId);
        parentBlock.innerBlocks.forEach((innerBlock) => {
            dispatch("core/block-editor").updateBlockAttributes(
                innerBlock.clientId,
                {
                    activeTab: uid,
                }
            );
        });
    };

    const addNewTab = () => {
        const tab = createBlock("ahsan03/tab");
        const position = tabs.length;
        dispatch("core/block-editor").insertBlock(tab, position, clientId);
        setAttributes({
            tabs: [
                ...tabs,
                {
                    uid: tab.clientId,
                    title: `Tab ${tabs.length + 1}`,
                    icon_url: "",
                },
            ],
        });
        setActiveTab(tab.clientId);
    };

    const tabTitleChange = (newValue) => {
        setAttributes({
            tabs: [
                ...tabs.map((tab) => {
                    return tab.uid === activeTab
                        ? {
                                ...tab,
                                title: newValue,
                          }
                        : tab;
                }),
            ],
        });
    };

    useEffect(() => {
        if (tabs.length && !activeTab) {
            setActiveTab(tabs[0].uid);
        }
    }, [tabs]);

    return (
        <>
            <div {...blockProps}>
                <div className="guten-tabs-nav">
                    {tabs.map((tab) => {
                        return (
                            <div
                                key={tab.uid}
                                className="guten-tab-item"
                                role="tab"
                                tabIndex="0"
                                onClick={() => setActiveTab(tab.uid)}
                            >
                                <div
                                    className={`guten-tab-link${
                                        tab.uid === activeTab
                                            ? " is-active"
                                            : ""
                                    }`}
                                >
                                    <img src={tab.icon_url} alt="" />
                                    {console.log("tabs tab", {
                                        tab,
                                    })}
                                    <RichText
                                        tagName="div"
                                        value={tab.title}
                                        onChange={tabTitleChange}
                                    />
                                </div>
                            </div>
                        );
                    })}
                    <Button
                        variant="primary"
                        icon="plus"
                        onClick={addNewTab}
                    >
                        {__("", "gtt")}
                    </Button>
                </div>
                <div className="guten-tab-content">
                    <InnerBlocks
                        allowedBlocks={["ahsan03/tab"]}
                        renderAppender={false}
                    />
                </div>
            </div>
        </>
    );
};

export default Edit;

我尝试的setTabIcon函数

const setTabIcon = (icon_url) => {
    const parentBlockIds =
        select("core/block-editor").getBlockParents(clientId);

    parentBlockIds.forEach((parentBlockId) => {
        const parentBlock = select("core/block-editor").getBlock(parentBlockId);
        console.log({ parentBlock });
    });
};

请问如何修改才能让上传的图片路径存入父块属性中?


解决方案

1. 修正Tab子块的setTabIcon函数

替换原来的setTabIcon函数,实现正确更新父块的tabs属性:

const setTabIcon = (icon_url) => {
    // 获取当前子块的直接父块ID
    const parentBlockIds = select("core/block-editor").getBlockParents(clientId);
    if (!parentBlockIds.length) return;

    const parentBlockId = parentBlockIds[0];
    const parentBlock = select("core/block-editor").getBlock(parentBlockId);
    const { tabs: parentTabs } = parentBlock.attributes;

    // 遍历父块tabs数组,匹配当前子块的uid并更新icon_url
    const updatedTabs = parentTabs.map(tabItem => {
        if (tabItem.uid === uid) {
            return { ...tabItem, icon_url };
        }
        return tabItem;
    });

    // 更新父块的属性
    dispatch("core/block-editor").updateBlockAttributes(parentBlockId, {
        tabs: updatedTabs
    });

    // 可选:同步更新子块自身的icon_url属性,方便子块内部使用
    setAttributes({ icon_url });
};

2. 确保Tab子块的属性定义包含icon_url

在Tab子块的block.json文件中,添加icon_url属性:

"attributes": {
    "uid": {
        "type": "string",
        "default": ""
    },
    "activeTab": {
        "type": "string",
        "default": ""
    },
    "icon_url": {
        "type": "string",
        "default": ""
    }
}

3. 验证父块渲染逻辑

父块(tabs.js)中已经存在<img src={tab.icon_url} alt="" />的渲染代码,只要父块的tabs数组里的项正确更新了icon_url,就能正常显示图标。


内容的提问来源于stack exchange,提问作者user15396919

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 00:05:28