- 前端
- CMS
【免费下载链接】wp-calypso
The JavaScript and API powered WordPress.com
导读
NavigationHeader是 WordPress.com 开源控制台 wp-calypso 中一个核心的布局组件,用于在页面顶部渲染"面包屑导航 + 标题 + 右侧操作区"的标准头部结构。本文以 client/components/navigation-header/README.md 为骨架,结合组件源码、样式文件、Storybook 故事与插件市场等真实业务用法,系统讲解其全部 Props、渲染逻辑(含"少于 2 个导航项不显示面包屑"等关键规则)、compactBreadcrumb移动端适配、屏幕选项 Tab 集成,以及返回链接变体calypso-navigation-header的使用方法。读完本文,你将能够在自己负责的 Calypso 页面中熟练接入并定制该头部组件。
组件定位与核心能力
NavigationHeader是一个基于 TSX 编写的头部组件,它解决的是页面级"导航上下文"的呈现问题:
- 面包屑导航:展示当前页在站点结构中的层级位置,帮助用户回溯;
- 标题与副标题:明确当前页面主题,并可内嵌帮助链接、说明文字;
- 右侧操作区(children):将"上传插件""管理插件"等页面级主操作按钮固定在头部右侧;
- 屏幕选项 Tab:可选接入 wp-admin 风格的 Screen Options。
从源码结构看,该目录实际包含两个组件实现(详见下文第五节),本文以 README 所描述的面包屑版本(client/components/navigation-header/index.tsx)为主,并补充其姊妹组件作对比。
快速上手:最小可用示例
README 给出了最基础的用法:传入navigationItems数组,并在组件内放置 children 作为右侧内容。
import NavigationHeader from 'calypso/components/navigation-header'; const navigationItems = [ { label: 'Plugins', href: `/plugins` }, { label: 'Search', href: `/plugins?s=woo` }, ]; function render() { return <NavigationHeader navigationItems={ navigationItems }>Children Item</NavigationHeader>; }以上代码渲染出一个包含两级面包屑(Plugins → Search)、且右侧渲染 "Children Item" 的页面头部。navigationItems中每项的href为可选项——不带href时该项仅作为纯文本标签(通常用于标记"当前所在页")。
Props 全解:参数、类型与默认行为
README 完整列出了该组件的 Props,下表逐一说明,并结合 index.tsx 的Props接口给出默认值与内部行为。
| Props | 类型 | 必填 | 说明与默认行为 |
|---|---|---|---|
navigationItems | { label: string; href?: string; helpBubble?: React.ReactElement; onClick?: () => void }[] | 否 | 面包屑导航项列表,默认[]。helpBubble可为该项附加悬浮帮助气泡,onClick可自定义点击行为 |
id | string | 否 | 渲染在<header>上的 DOM id,默认为空字符串 |
className | string | 否 | 附加到包裹组件的 class,默认空字符串,最终通过clsx合并为navigation-header |
children | nodes | 否 | 渲染在最右侧的操作区内容 |
compactBreadcrumb | boolean | 否 | 面包屑只显示上一级并显示 "Back" 文案,常用于移动端 |
title | string | 否 | 头部标题,可为字符串或 ReactNode |
subtitle | string | 否 | 头部副标题,可为字符串或 ReactNode |
screenReader | string | 否 | 屏幕阅读器专用文案,视觉上隐藏 |
mobileItem | TBreadcrumbItem | 否 | 移动端单独指定的面包屑项(透传给 Breadcrumb) |
alwaysShowTitle | boolean | 否 | 强制始终显示标题,默认false |
screenOptionsTab | string | 否 | 传入 wp-admin 路径后渲染 Screen Options Tab |
style | object | 否 | 作用于<header>的内联样式 |
loggedIn | boolean | 否 | 登录态标识,默认true,参与标题显隐判定 |
注意:
Props接口中title/subtitle/screenReader的实际类型是string | ReactNode(见 index.tsx),README 中标注的string是简化描述,实战中可以传入组件或富文本节点。
navigationItems 项结构
每一项遵循 Breadcrumb 的Item类型(组件内部通过import Breadcrumb, { Item as TBreadcrumbItem }引入,见 index.tsx):
{ label: 'Plugins', // 展示文本 href: '/plugins', // 可选,跳转地址 helpBubble: <InfoPopover />, // 可选,悬浮帮助气泡 onClick: () => {}, // 可选,自定义点击处理 }关键渲染规则:标题与面包屑的显隐逻辑
README 中强调 "It will not show less than 2 items"(导航项少于 2 个时不显示面包屑),这一定义在源码中有更精确的实现,见 index.tsx:
const [ showCrumbs, setShowCrumbs ] = useState( false ); const showTitle = alwaysShowTitle || ( navigationItems.length < 2 && loggedIn ); useEffect( () => { setShowCrumbs( checkShouldShowBreadcrumb() ); }, [] );由此可以提炼出三条核心规则:
- 面包屑显隐受 URL 参数控制:
checkShouldShowBreadcrumb()会检查当前 URL 的options查询参数,若其中包含noCrumbs则隐藏面包屑(index.tsx)。源码注释说明:已过期的 eCommerce 试用站点无法访问面包屑暴露出的设置等页面,因此用该参数隐藏面包屑。组件在挂载时通过useEffect一次性读取该参数。 - 标题优先于面包屑:当
navigationItems.length < 2且用户已登录时,隐藏面包屑、改为显示标题(showTitle为真)。也就是说标题与面包屑是互斥呈现的——有足够层级时给面包屑,层级不足时给标题。alwaysShowTitle可绕过该判定强制显示标题。 - 服务端渲染安全:
checkShouldShowBreadcrumb在typeof window === 'undefined'(SSR 环境)时直接返回false,避免服务端读取window.location报错。
渲染结构总览
组件最终输出如下 DOM 结构(对应 index.tsx):
<header id="..." class="navigation-header ..."> <div class="navigation-header__container"> <div class="navigation-header__main"> <!-- 可选:ScreenOptionsTab --> <ScreenOptionsTab wpAdminPath="..." /> <!-- 可选:Breadcrumb(showCrumbs 为真时) --> <Breadcrumb items={...} compact={...} hideWhenOnlyOneLevel /> <!-- 可选:FormattedHeader(showTitle 为真时) --> <FormattedHeader align="left" headerText={title} subHeaderText={subtitle} screenReader={...} /> <!-- 右侧操作区 --> <div class="navigation-header__actions">{ children }</div> </div> </div> </header>其中的Container通过 emotionstyled.div实现(index.tsx):在.main.is-wide-layout下水平居中;在.stats/.stats__email-detail页面中将宽度约束为max-width: 1224px并居中——这是为统计(Stats)页面做的特殊适配。
依赖的子组件
- Breadcrumb:来自
calypso/components/breadcrumb,接收items、mobileItem、compact并设置了hideWhenOnlyOneLevel(仅一级时不渲染); - FormattedHeader:来自
calypso/components/formatted-header,负责标题/副标题的排版与屏幕阅读器文案; - ScreenOptionsTab:来自
calypso/components/screen-options-tab,当同时传入screenOptionsTab与children时,<header>会追加navigation-header__screen-options-tabclass(见 index.tsx),用于样式补偿(详见下节)。
样式与响应式行为
该组件的样式拆分为两个 SCSS 文件,各有分工:
style.scss(面包屑版本主样式)
style.scss 定义.navigation-header的盒模型与内部布局:
- 桌面端
padding: 0 0 16px 0,移动端(max-width: $break-small)改为四周16px内边距; .navigation-header__main使用display: flex; justify-content: space-between让标题居左、操作区居右;- 面包屑
.breadcrumbs li:普通项使用灰色(var(--studio-gray-60, #50575e)),最后一项(当前页)加深为var(--studio-gray-100, #101517); - 副标题
.formatted-header__subtitle在移动端默认隐藏,min-width: $break-small以上才显示;移动端改由.info-popover承载说明内容(display: inline-block),即"小屏藏文字、留气泡"的响应式策略; .navigation-header__actions采用display: flex; gap: 16px排列右侧操作按钮。
navigation-header.scss(返回链接变体样式)
navigation-header.scss 服务于姊妹组件calypso-navigation-header:
- 头部使用
flex-direction: column上下分区:上为.calypso-navigation-header__head(返回链接区),下为__body(标题与右侧操作区,justify-content: space-between); - 返回链接
.calypso-navigation-header__back-link使用灰色(var(--wp-components-color-gray-600, #666)),hover 加深;源码注释特别说明该样式提高了选择器优先级(& &__back-link)以覆盖 Atomic 站点上a的默认链接色; - 标题字体采用 "SF Pro Display",
font-size: 20px; font-weight: 500,副标题使用$font-sf-pro-text与var(--wp-components-color-gray-700); - 当存在 Screen Options Tab 时,移动端
padding-top: 38px(30px Tab 高度 + 8px gap),桌面端回退为$grid-unit-20(16px),避免 Tab 与操作按钮在移动端重叠。
姊妹组件:返回链接版calypso-navigation-header
同目录下的 navigation-header.tsx 是面包屑版之外的另一种头部形态,专为"详情页返回上一级"场景设计,其 Props 与面包屑版互补:
| Props | 说明 |
|---|---|
titleProps | { title, titleLogo, subtitle },标题组;titleLogo会在标题前渲染 24×24 的 Logo 位 |
backLinkProps | { url, text, onBackClick },返回链接;提供url时自动在头部上方渲染 "← Back" 按钮 |
titleElement/headElement | 自定义节点,分别覆盖默认标题区与默认头部区渲染 |
rightSection | 等价于面包屑版的children,渲染在最右侧 |
hasScreenOptionsTab | 为真时追加calypso-navigation-header__screen-options-tabclass |
其返回按钮的导航逻辑值得注意(navigation-header.tsx):
- 先调用
popCurrentScreenFromHistory()弹出统计页维护的导航历史栈(来自calypso/my-sites/stats/hooks/use-stats-navigation-history); - 若提供了
onBackClick回调则直接执行; - 否则对站内相对路径(非
http:///https://开头)通过calypso-router的page()做 SPA 路由跳转; - 对同源绝对 URL 使用
window.location.href跳转。
两者分别适用于"层级导航"(面包屑)与"单级返回"(Back 链接)两种头部信息架构,可按页面形态选用。
真实业务用法:插件市场的 NavigationHeader
组件在 client/my-sites/plugins/plugins-navigation-header/index.jsx 中有完整实践,可作为教科书式用法:
<NavigationHeader className="plugins-navigation-header" compactBreadcrumb={ isMobile } // 移动端切换为紧凑 Back 模式 ref={ navigationHeaderRef } title={ translate( 'Plugins {{wbr}}{{/wbr}}marketplace', { components: { wbr: <wbr /> }, } ) } loggedIn={ isLoggedIn } > <ManageButton ... /> <UploadPluginButton ... /> </NavigationHeader>该示例展示了几个进阶要点:
- 面包屑动态化:通过 Redux 的
appendBreadcrumb/resetBreadcrumbs动作维护全局面包屑状态,再经由useSelector( getBreadcrumbs )读取后传入组件——面包屑不再硬编码,而是随路由(站点、分类、搜索词)实时重建,见 plugins-navigation-header/index.jsx; - 移动端适配:
compactBreadcrumb={ isMobile }由useBreakpoint( '<960px' )驱动,小屏自动退化为紧凑面包屑; - 右侧操作区组合:
children中放入"Installed plugins"(ManageButton)与"Upload"(UploadPluginButton)两个按钮,按钮会根据登录态、站点类型(Jetpack/Atomic)、站点能力(WPCOM_FEATURES_MANAGE_PLUGINS等)动态显隐; loggedIn语义:未登录访问时showTitle判定为假,避免未登录页面同时出现空面包屑与标题。
除插件市场外,client/my-sites/plugins/plans/index.tsx、plugin-upload/index.jsx、plugins-browser/index.jsx、mailpoet-upgrade/index.tsx等页面均使用该组件,说明它已是插件功能域的标准头部方案。
Storybook 可视化调试
组件自带 Storybook 故事(stories/navigation-header.stories.tsx),注册为client/components/NavigationHeader,采用layout: 'fullscreen'以便完整观察头部效果,并开启autodocs。现有故事覆盖四个场景:
Basic:仅标题的基础头部;WithBackLink:带 "Back to Dashboard" 返回链接的头部;WithDownloadAndAction:返回链接 + 右侧 "Download CSV" 下载链接;WithScreenOptions:开启 Screen Options Tab,并展示onBackClick回调与右侧 "Post" 主操作按钮的完整形态。
开发新用法时可参考这些故事快速起手,或在本地通过 Storybook 对组件做交互验证。
完整可运行示例
综合 README 示例与 docs/example.jsx(组件文档示例页),给出一个覆盖多数 Props 的完整写法:
import { translate } from 'i18n-calypso'; import NavigationHeader from 'calypso/components/navigation-header'; import InlineSupportLink from 'calypso/components/inline-support-link'; import InstallThemeButton from 'calypso/my-sites/themes/install-theme-button'; const navigationItems = [ { label: 'Domains', href: `/domains` }, { label: 'thisisanexample.wordpress.com', href: `/domains/thisisanexample.wordpress.com` }, { label: 'Transfer', href: `/domains/thisisanexample.wordpress.com/transfer` }, ]; <NavigationHeader navigationItems={ navigationItems } compactBreadcrumb={ false } mobileItem={ null } title="Title example" subtitle="Subtitle example" screenReader="Screen reader example" />; // 标题 + 内嵌帮助链接的副标题 + 右侧按钮 <NavigationHeader navigationItems={ [] } title={ translate( 'Themes' ) } subtitle={ translate( 'Select or update the visual design for your site. {{learnMoreLink}}Learn more{{/learnMoreLink}}.', { components: { learnMoreLink: <InlineSupportLink supportContext="themes" showIcon={ false } />, }, } ) } > <InstallThemeButton /> </NavigationHeader>;第二个示例展示了两个值得留意的细节:
navigationItems传空数组时组件会自动退化为"仅标题"模式(配合showTitle判定);subtitle并非纯文本——它借助InlineSupportLink(来自calypso/components/inline-support-link)在副标题中嵌入 "Learn more" 支持链接,配合translate的components机制完成 i18n 插值,这是 Calypso 组件组合的典型用法。
小结
NavigationHeader是 wp-calypso 页面头部的"标准答案":面包屑与标题按导航层级智能互斥呈现,右侧操作区天然支持任意 React 节点,Screen Options Tab 无缝桥接 wp-admin 体验,compactBreadcrumb一行属性完成移动端适配。若你正在 Calypso 中新增页面,可直接参考 client/my-sites/plugins/plugins-navigation-header/index.jsx 的 Redux 动态面包屑模式;若页面属于"详情页返回"型信息架构,则可选用同目录的返回链接变体 navigation-header.tsx。相关源码、文档示例(docs/example.jsx)与 Storybook 故事均可作为后续开发的第一手参考资料。
- 前端
- CMS
【免费下载链接】wp-calypso
The JavaScript and API powered WordPress.com
相关推荐
BootstrapVue导航组件深度解析:Navbar、Tabs与面包屑
BootstrapVue导航组件深度解析:Navbar、Tabs与面包屑 在现代Web应用开发中,导航系统是用户体验的核心组成部分。BootstrapVue提供
前端UI组件KiloClaw Telegram 接入指南:Bot 配置、群聊权限与访问控制全流程
KiloClaw Telegram 接入指南:Bot 配置、群聊权限与访问控制全流程 KiloClaw 是 Kilo 提供的托管式 OpenClaw 服务,支持
前端CMSDexed与硬件DX7无缝对接:SysEx数据传输完整教程
Dexed与硬件DX7无缝对接:SysEx数据传输完整教程 Dexed作为一款功能强大的DX7 FM多平台插件,不仅能完美模拟经典DX7的声音特性,还支持与硬件
音视频
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考