Gutenberg 站点编辑器路由系统解析:Site Editor Routes 的 Areas 与 canvasMode 机制
2026/9/17 20:58:02 网站建设 项目流程

Gutenberg 站点编辑器路由系统解析:Site Editor Routes 的 Areas 与 canvasMode 机制

【免费下载链接】gutenbergThe Block Editor project for WordPress and beyond. Plugin is available from the official repository.项目地址: https://gitcode.com/GitHub_Trending/gu/gutenberg

站点编辑器(Site Editor)的左侧导航、内容面板、预览画布与移动端布局,全部由一个基于「路由 + Areas」的组合式框架驱动。本文以 packages/edit-site/src/components/site-editor-routes/README.md 为核心,结合该目录下全部路由定义、store 层的注册动作与 layout 渲染源码,完整讲解 Site Editor Routes 的组成结构、各 Area 在不同视口与canvasMode下的渲染规则,以及如何阅读与扩展一条新路由。

读完本文,你将掌握:一条站点编辑器路由由哪些字段构成、sidebar/content/preview/edit/mobileSidebar/mobileContent六个 Area 各自的职责与优先级、canvasMode切换为edit时布局如何收敛为全屏画布,以及这套机制在首页、样式、模板、页面、图案、导航等真实路由中如何落地。

一、为什么需要「Site Editor Routes」

站点编辑器是一个复杂的多页面应用,它同时承载了:

  • 站点首页(/)的概览导航;
  • 样式(Styles)与 Stylebook 预览;
  • 模板(Templates)、模板部件(Template Parts)、页面(Pages)的浏览与编辑;
  • 图案(Patterns)与导航(Navigation)的管理;
  • 以及一条兜底的 404 路由。

传统做法是在一个巨型组件里用条件渲染堆叠所有页面,而 Gutenberg 的做法是把每个页面抽象为一条「路由」,每条路由声明自己需要占据哪些「区域(Areas)」,再由统一的 Layout 组件根据**视口宽度(是否移动端)**与canvasMode(编辑画布模式)决定每个区域最终渲染在哪里、以什么形式出现。

这套体系的核心代码集中在 site-editor-routes 目录,共定义了 14 条路由(homeidentitystylesnavigationnavigation-itempatternspattern-itemtemplate-part-itemtemplatestemplate-itempagespage-itemstylebooknotfound),而 layout/index.jsx 负责最终将这些 Areas 摆放到屏幕上。

二、Areas:路由声明的六个渲染区域

在 README 中,一个关键概念是Area。每条路由可以通过areas字段声明最多六个区域,每个区域都是一个 React 节点或返回节点的函数。这些区域并非都会被渲染,是否渲染取决于canvasMode与视口宽度。

2.1canvasMode为非edit时的渲染规则

canvasMode不是edit(即处于浏览/导航模式)时,可用区域及其渲染行为如下表(原文完整继承):

Area非移动端视口移动端视口
sidebar始终渲染。仅当未提供任何移动端区域(mobileSidebarmobileContentpreview)时渲染。
content提供了才渲染。不渲染。
preview提供了才渲染。不渲染。
edit提供了才渲染。不渲染。
mobileSidebar不渲染提供了且未提供mobileContent时,以全屏方式渲染(使用主题化的侧边栏背景)。
mobileContent不渲染提供了则渲染,全屏显示(使用白色内容背景)。

要点提炼:

  • sidebar是唯一「始终渲染」的桌面端区域,它承载左侧导航栏;
  • contentpreviewedit在桌面端都是「可选渲染」的补充区域,用于承载中间列表或右侧画布;
  • 移动端是「二选一」结构:有mobileContent时优先显示内容,否则回退到mobileSidebar;两者都缺省时才回退到桌面端sidebar

2.2canvasModeedit时的渲染规则

canvasModeedit(进入某个实体的编辑画布)时,布局收敛为全屏编辑模式:

Area非移动端视口移动端视口
preview提供了则全屏渲染;否则显示一个空白侧边栏。提供了则全屏渲染;否则显示一个空白侧边栏。

也就是说,进入canvasMode=edit后,sidebarcontentedit均不再按浏览模式渲染,只剩preview一个区域独占整个画布——这正是用户点击某个模板、页面或图案后看到的「全屏编辑器」形态。

三、路由的结构:name、path、areas 与 widths

每一条路由都是导出为一个普通对象。以 home.jsx 为例,其结构为:

export const homeRoute = { name: 'home', path: '/', areas: { sidebar( { siteData } ) { ... }, preview( { siteData } ) { ... }, mobileSidebar( { siteData } ) { ... }, }, };

字段说明:

字段作用
name路由唯一标识,用于注册与注销,也作为routeKey参与布局渲染。
path路由路径。支持静态路径(/styles)、路径参数(/page/:postId)以及通配段(/wp_template/*postId/template),并支持*通配符作为 404 兜底(见 notfound.jsx)。
areas一个对象,键为上述六个 Area 名,值为 React 元素或( { siteData, query } ) => ReactNode形式的函数。函数形式可以拿到站点数据与 URL 查询参数,按需返回null/undefined表示「不渲染」。
widths可选,用于指定各 Area 的宽度,例如content: 380(像素),也支持异步函数动态计算宽度。

3.1 常见路径模式一览

从源码中可以整理出全部路由的路径定义:

路由path说明
home/站点首页
identity/identity站点身份(logo、标题等)
styles/styles全局样式
stylebook/stylebook经典主题下的 Stylebook 预览
navigation/navigation导航菜单列表
navigation-item/wp_navigation/:postId单个导航菜单编辑
patterns/pattern图案列表
pattern-item/wp_block/:postId单个图案编辑
templates/template模板列表
template-item/wp_template/*postId单个模板编辑
template-part-item/wp_template_part/*postId单个模板部件编辑
pages/page页面列表
page-item/page/:postId单个页面编辑
notfound*404 兜底

可以看到:内容实体(页面、模板、图案、导航)遵循「列表路径为/xxx、详情路径为/xxx/:postId」的约定,其中模板与模板部件因实体 ID 可能包含斜杠,使用了*postId通配捕获段。

四、路由注册:从模块导出到 store

路由对象在 index.js 中汇总为routes数组,并通过useRegisterSiteEditorRoutes()这个 Hook 完成注册:

export function useRegisterSiteEditorRoutes() { const registry = useRegistry(); const { registerRoute } = unlock( useDispatch( siteEditorStore ) ); useEffect( () => { registry.batch( () => { routes.forEach( registerRoute ); } ); }, [ registry, registerRoute ] ); }

关键细节:

  • registerRoute@wordpress/datastore 的私有 action,定义于 private-actions.js,通过unlock()解锁后使用;
  • 注册动作REGISTER_ROUTE在 reducer.js 中把路由对象追加到state.routes数组;对应的unregisterRoute通过UNREGISTER_ROUTEname过滤移除;
  • 读取端使用私有 selectorgetRoutes(见 private-selectors.js),在 app/index.jsx 中通过unlock( select( editSiteStore ) ).getRoutes()取得全部路由,作为routes属性传入<RouterProvider>,交给@wordpress/router做匹配与分发。

由于注册发生在useEffect中,且整批路由一次性批量注册,因此路由表在应用挂载后即完整可用,这与「路由匹配-渲染」的解耦设计是一致的。

五、Layout:Areas 的最终摆布与 canvasMode 语义

路由只负责「声明」,真正的布局逻辑在 layout/index.jsx 中。结合源码可以验证 README 中的每一条规则:

5.1 桌面端布局

  • sidebar始终渲染在左侧(areas.sidebar,被包裹在SidebarNavigationProvider中,见 layout/index.jsx);
  • content仅在非移动端且canvas !== 'edit'时渲染(! isMobileViewport && areas.content && canvas !== 'edit'),并使用widths?.content控制最大宽度;
  • edit区域同样仅在非移动端且canvas !== 'edit'时渲染;
  • preview在非移动端渲染于画布容器edit-site-layout__canvas-container中,支持可拖拽的canvasResizer(layout/index.jsx);
  • canvas === 'edit'时,布局类名追加is-full-canvas,导航侧栏被隐藏,preview区域独占全屏。

5.2 移动端布局

移动端分支(isMobileViewport && hasMobileAreas)验证了 README 的移动规则:

  • 优先渲染areas.mobileContent,且外层套上ThemeProvider color={ CONTENT_COLOR }(白色内容背景);
  • 若未提供mobileContent,则回退渲染areas.mobileSidebar(主题化侧边栏背景);
  • 两者都未提供时,桌面端的sidebar才会作为兜底出现;
  • canvas === 'edit'时,移动端同样直接渲染areas.preview,且以白色内容背景包裹。

5.3canvasMode从哪来

canvasMode(源码中通常以canvas表示,取值为'edit'或其他浏览模式)来自 URL 查询参数,通过@wordpress/routeruseLocation()读取。源码中有多处将其置为edit的操作,例如 sidebar-navigation-screen-global-styles/index.jsx 中history.navigate( addQueryArgs( path, { canvas: 'edit' } ) ),以及 block-editor/use-editor-iframe-props.js 中的相关跳转。这解释了「从浏览视图点击某个模板/页面 → 进入全屏编辑」这一交互链路。

六、真实路由逐条拆解

6.1 首页路由(home)

home.jsx 是最能体现 Areas 动态性的例子。它的三个区域都依赖siteData异步判断:

  • sidebar在主题数据未加载时返回null(等待数据);
  • 主题为块主题或经典主题支持 Stylebook 时渲染SidebarNavigationScreenMain,否则渲染SidebarNavigationScreenUnsupported(不支持提示);
  • preview仅在支持的条件下渲染<Editor isHomeRoute renderingMode="template-locked" />,否则返回undefined(画布留空);
  • mobileSidebarsidebar逻辑一致。

这里的siteData来自路由 area 的 resolver 提供的站点数据,辅助函数定义在 utils.js:

  • isThemeDataLoaded( siteData ):通过currentTheme是否存在判断 REST 主题数据是否已加载;
  • isClassicThemeWithStyleBookSupport( siteData ):判断经典主题是否支持 Stylebook——即!is_block_theme && ( theme_supports['editor-styles'] || supportsLayout )

6.2 样式路由(styles)与 Stylebook

styles.jsx 同时用到了contentmobileContent

areas: { content: <SidebarGlobalStyles />, sidebar: <SidebarNavigationScreenGlobalStyles backPath="/" />, preview: ( { siteData } ) => <StylesPreviewArea siteData={ siteData } />, mobileContent: <SidebarGlobalStyles />, }, widths: { content: 380 },
  • 桌面端:左侧sidebar(全局样式导航)+ 中间content(全局样式设置面板,宽度 380px)+ 右侧preview画布;
  • 移动端:直接用mobileContent全屏展示全局样式设置;
  • StylesPreviewArea会根据 URL 查询参数preview=stylebook决定画布渲染 Stylebook 还是编辑器;StyleBookPreviewArea还会从query.section读取当前浏览的区块分类,并调用useGlobalStyles()传入userConfig,使未保存的全局样式修改能实时反映到预览中。

同样与 Stylebook 相关的还有 stylebook.jsx:它专为「经典主题但支持 Stylebook」的场景服务,桌面端在preview中渲染StyleBookPreview isStatic,移动端则在mobileContent中渲染同样的静态预览。

6.3 模板与页面列表(templates / pages)

template-item.jsx 与 pages.jsx 展示了异步 Area 与动态宽度的用法:

  • preview区域是async函数:它通过@wordpress/viewsloadView()读取当前activeView对应的视图配置(view_list中匹配activeViewview),只有当视图类型为list时才返回<Editor />(此时桌面端将 sidebar+content 与画布并排),否则返回undefined
  • widths.content同样声明为async,依据视图是否为列表动态返回380(列表宽度)或undefined(不限制)——例如 templates.jsx;
  • 内容区域(content/mobileContent)在块主题下渲染PageTemplatesPostList,非块主题则返回undefined并让sidebar展示SidebarNavigationScreenUnsupported
  • 单个实体的编辑路由(如 template-item.jsx、page-item.jsx、pattern-item.jsx、navigation-item.jsx、template-part-item.jsx)结构高度一致:sidebar提供返回列表的导航,preview直接渲染<Editor />进入全屏编辑(源码注释明确写到 "Also rendered on mobile, where this route is only reached at canvas=edit",印证了 README 中「edit 模式下仅preview渲染」的规则)。

6.4 兜底路由(notfound)

notfound.jsx 使用path: '*'捕获所有未匹配路径,在sidebar/mobileSidebar/content中分别渲染错误提示NotFoundError(基于Notice status="error"),保证站点编辑器在任何无效 URL 下都有友好的反馈。

七、如何新增或修改一条路由

基于以上机制,在站点编辑器中接入新页面的一般步骤为(仅说明查看与理解方式,仓库为只读):

  1. packages/edit-site/src/components/site-editor-routes/下新建一个路由模块,导出{ name, path, areas }对象;
  2. 按需求声明areas:桌面浏览模式至少提供sidebar;如需中间面板补充content;如需画布预览补充preview;移动端体验考虑补充mobileContentmobileSidebar
  3. 若需要固定宽度面板(如 380px 的设置栏),在widths.content中声明;
  4. 在 index.js 的routes数组中追加该路由对象,useRegisterSiteEditorRoutes()会在应用启动后自动将其注册进editSiteStore
  5. areas中的函数参数{ siteData, query }可用于主题能力判断(如is_block_theme)与 URL 查询参数分支(如query.preview === 'stylebook'query.categoryId),在数据未就绪时应返回null等待加载。

八、总结

Site Editor Routes 的「路由 + Areas」抽象,把站点编辑器的多页面布局问题拆解成了清晰的三层:路由层name/path/areas/widths的声明)、注册层(通过registerRoute私有 action 进入 store 的routes状态)、渲染层(Layout 依据isMobileViewportcanvas决定每个 Area 的最终位置与形态)。README 中关于canvasMode与移动端的六行规则,在 layout/index.jsx 中都有对应的源码分支与之严格对应,是本项目响应式站点编辑器架构最值得研读的起点。

【免费下载链接】gutenbergThe Block Editor project for WordPress and beyond. Plugin is available from the official repository.项目地址: https://gitcode.com/GitHub_Trending/gu/gutenberg

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询