ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Gutenberg 定制器小部件数据存储:core/customize-widgets 的 Inserter 状态管理完全指南

Gutenberg 定制器小部件数据存储:core/customize-widgets 的 Inserter 状态管理完全指南 Gutenberg 定制器小部件数据存储core/customize-widgets 的 Inserter 状态管理完全指南【免费下载链接】gutenbergThe Block Editor project for WordPress and beyond. Plugin is available from the official repository.项目地址: https://gitcode.com/GitHub_Trending/gu/gutenberg在 GutenbergWordPress 块编辑器项目中wordpress/customize-widgets包负责将经典「外观 → 自定义 → 小部件」界面改造为基于块的编辑器。支撑这一改造的核心状态层是命名空间为core/customize-widgets的 Redux 数据存储data store。本文以官方数据参考文档为骨架结合仓库源码系统讲解该 store 暴露的isInserterOpened选择器与setIsInserterOpenedAction 的签名、用法、底层状态结构以及它们如何与 WordPress CustomizerBackbone 架构完成双向同步帮助你掌握在自定义组件中读写块插入器block inserter开关状态的标准姿势。一、认识 core/customize-widgets 数据存储core/customize-widgets是 customize-widgets 包 内置的全局数据 store其 store 名称命名空间定义在 store/constants.js 中export const STORE_NAME core/customize-widgets;与 Gutenberg 中其他数据 store 一样它通过wordpress/data的createReduxStore创建并立即register注册见 store/index.jsimport { createReduxStore, register } from wordpress/data; import reducer from ./reducer; import * as selectors from ./selectors; import * as actions from ./actions; import { STORE_NAME } from ./constants; const storeConfig { reducer, selectors, actions, }; export const store createReduxStore( STORE_NAME, storeConfig ); register( store );该 store 的核心职责是跟踪插入器面板的打开/关闭状态。从 store/reducer.js 可以看出整个 store 目前只维护一个 state 切片blockInserterPanelfunction blockInserterPanel( state false, action ) { switch ( action.type ) { case SET_IS_INSERTER_OPENED: return action.value; } return state; } export default combineReducers( { blockInserterPanel, } );默认值为false插入器默认关闭仅响应SET_IS_INSERTER_OPENED这一种 action 类型直接将action.value写入 state该值既可以是布尔值也可以是包含插入点信息的对象下文详解。提示注册好的 store 可通过import { store as customizeWidgetsStore } from wordpress/customize-widgets拿到 store 定义包含STORE_NAME并在useSelect/useDispatch/select/dispatch中使用。二、选择器Selectors2.1 isInserterOpened —— 查询插入器是否打开签名isInserterOpened( state ) → boolean功能返回插入器当前是否处于打开状态。参数参数类型说明stateObject全局应用状态由wordpress/data自动注入返回值boolean—— 插入器打开为true关闭为false。源码实现store/selectors.js非常直接本质上是对state.blockInserterPanel的布尔化判断export function isInserterOpened( state ) { return !! state.blockInserterPanel; }由于blockInserterPanel可能是布尔值也可能是对象插入点!!转换保证两种形态下都能给出明确的布尔结果。React 组件中的典型用法官方文档示例使用useSelect订阅状态import { store as customizeWidgetsStore } from wordpress/customize-widgets; import { __ } from wordpress/i18n; import { useSelect } from wordpress/data; const ExampleComponent () { const { isInserterOpened } useSelect( ( select ) select( customizeWidgetsStore ), [] ); return isInserterOpened() ? __( Inserter is open ) : __( Inserter is closed. ); };2.2 __experimentalGetInsertionPoint —— 获取插入点实验性除了文档中收录的isInserterOpenedselectors.js 还提供了一个实验性选择器用于读取插入点信息const EMPTY_INSERTION_POINT { rootClientId: undefined, insertionIndex: undefined, }; export function __experimentalGetInsertionPoint( state ) { if ( typeof state.blockInserterPanel boolean ) { return EMPTY_INSERTION_POINT; } return state.blockInserterPanel; }当blockInserterPanel是布尔值时返回空插入点{ rootClientId: undefined, insertionIndex: undefined }当它被设置为对象带插入点时原样返回。该选择器以__experimental前缀标识属于实验性 API生产代码使用前需自行评估稳定性。三、ActionsetIsInserterOpened签名setIsInserterOpened( value ) → Object功能返回一个用于打开/关闭插入器的 action 对象。参数参数类型说明valueboolean \| Objecttrue表示打开插入器false表示关闭若要指定插入点可传入对象value.rootClientIdstring插入目标块的根 client IDvalue.insertionIndexnumber插入位置的索引返回值Object—— 形如{ type: SET_IS_INSERTER_OPENED, value }的 action 对象。源码实现store/actions.jsexport function setIsInserterOpened( value ) { return { type: SET_IS_INSERTER_OPENED, value, }; }React 组件中的典型用法官方文档示例通过useDispatch获取派发函数并结合组件本地状态实现开关import { useState } from react; import { store as customizeWidgetsStore } from wordpress/customize-widgets; import { __ } from wordpress/i18n; import { useDispatch } from wordpress/data; import { Button } from wordpress/components; const ExampleComponent () { const { setIsInserterOpened } useDispatch( customizeWidgetsStore ); const [ isOpen, setIsOpen ] useState( false ); return ( Button onClick{ () { setIsInserterOpened( ! isOpen ); setIsOpen( ! isOpen ); } } { __( Open/close inserter ) } /Button ); };需要留意的是文档与源码中setIsInserterOpened( ! isOpen )接收的是布尔值。当需要指定插入位置时则应传入对象形态例如dispatch( customizeWidgetsStore ).setIsInserterOpened( { rootClientId: some-root-client-id, insertionIndex: 0, } );传入对象后isInserterOpened()依然返回true因为对象会被!!转为布尔真同时__experimentalGetInsertionPoint()会返回该对象供上层逻辑决定具体插入到哪个块的哪个位置。四、源码中的真实调用场景该 store 并非孤立设计而是深度嵌入了「小部件自定义器」的完整交互闭环。理解这些调用点有助于把握 API 的实际语义。4.1 Header 工具栏的开关按钮在 components/header/index.jsx 中顶部工具栏的 Add block按钮直接以isInserterOpened作为isPressed状态并调用setIsInserterOpened切换ToolbarButton classNamecustomize-widgets-header-toolbar__inserter-toggle isPressed{ isInserterOpened } variantprimary icon{ plus } label{ _x( Add block, Generic label for block inserter button ) } onClick{ () { setIsInserterOpened( ( isOpen ) ! isOpen ); } } /注意这里使用了函数式更新( isOpen ) ! isOpen这与 use-inserter.js 中暴露的setIsInserterOpened包装函数保持一致——该包装函数支持传入函数时自动读取当前 store 值求反避免闭包捕获过期状态。4.2 useInserter 自定义 Hookcomponents/inserter/use-inserter.js 是连接 React 状态与 Customizer 原生插入器Backbone 对象的桥梁export default function useInserter( inserter ) { const isInserterOpened useSelect( ( select ) select( customizeWidgetsStore ).isInserterOpened(), [] ); const { setIsInserterOpened } useDispatch( customizeWidgetsStore ); useEffect( () { if ( isInserterOpened ) { inserter.open(); } else { inserter.close(); } }, [ inserter, isInserterOpened ] ); return [ isInserterOpened, useCallback( ( updater ) { let isOpen updater; if ( typeof updater function ) { isOpen updater( selectStore( customizeWidgetsStore ).isInserterOpened() ); } setIsInserterOpened( isOpen ); }, [ setIsInserterOpened ] ), ]; }可以看到React 侧的 store 状态是唯一事实来源source of truth当状态变化时通过inserter.open() / inserter.close()驱动 Customizer 原生 UI 展开/收起而第二返回值允许调用方以( isOpen ) ! isOpen形式更新状态。4.3 与 CustomizerBackbone的双向同步controls/inserter-outer-section.js 展示了反向通道Customizer 原生事件也会反向写入 store从而与 React 保持同步。Escape 关闭当插入器展开时按下Escape会调用dispatch( customizeWidgetsStore ).setIsInserterOpened( false )关闭插入器采用捕获阶段监听先于其他监听器执行展开状态回写this.expanded.bind( ... )监听 Customizer 面板的展开/收起事件当不是内部动作触发时将this.expanded()结果通过setIsInserterOpened写回 store防循环机制通过isFromInternalAction标志避免React → Customizer → React的无限循环焦点管理打开时在completeCallback中把焦点移到搜索框跳过第一个关闭按钮关闭时若焦点位于插入器内部则归还到打开前的元素。因此setIsInserterOpened不仅服务于 React 组件也是 Backbone 与 React 之间状态同步的写入入口。五、组合实践构建一个完整的开关组件将上述 API 组合起来即可实现一个与 Customizer 原生行为完全同步的插入器开关组件import { store as customizeWidgetsStore } from wordpress/customize-widgets; import { __ } from wordpress/i18n; import { useSelect, useDispatch } from wordpress/data; import { Button } from wordpress/components; const InserterToggle () { const isInserterOpened useSelect( ( select ) select( customizeWidgetsStore ).isInserterOpened(), [] ); const { setIsInserterOpened } useDispatch( customizeWidgetsStore ); return ( Button isPressed{ isInserterOpened } onClick{ () setIsInserterOpened( ( isOpen ) ! isOpen ) } { isInserterOpened ? __( Close inserter ) : __( Open inserter ) } /Button ); };六、使用注意事项适用前提core/customize-widgets服务于「小部件自定义器」场景Appearance Customize Widgets该包官方注明主要面向 WordPress 核心使用通用项目引入需自行评估其稳定性见 packages/customize-widgets/README.md。安装方式在支持 ES2015 的环境中可通过npm install wordpress/customize-widgets安装使用。插入点参数setIsInserterOpened的对象形态参数rootClientId/insertionIndex是可选的高级用法普通开关场景传布尔值即可。实验性 API__experimentalGetInsertionPoint带实验前缀未出现在正式文档中接入前需确认目标 WordPress/Gutenberg 版本支持。状态是双向的Escape 键、Customizer 面板手动收起等操作都会回写该 store因此不要假设只有你的组件能改变插入器状态读取端应始终以useSelect订阅为准。通过本文你可以基于core/customize-widgets的isInserterOpened选择器与setIsInserterOpenedAction在任何 React 组件中精确感知并控制小部件自定义器内块插入器的开合状态同时理解它与 Customizer 原生 UI 的同步机制为自定义小部件编辑体验的开发打下坚实基础。【免费下载链接】gutenbergThe Block Editor project for WordPress and beyond. Plugin is available from the official repository.项目地址: https://gitcode.com/GitHub_Trending/gu/gutenberg创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表