首页
/ ant-design Breadcrumb 面包屑组件实战:items 配置、路由参数替换、Semantic DOM 与主题 Token 定制

ant-design Breadcrumb 面包屑组件实战:items 配置、路由参数替换、Semantic DOM 与主题 Token 定制

2026-09-06 15:56:51作者:伍霜盼Ellen

本篇基于 ant-design 仓库中的面包屑组件文档 components/breadcrumb/index.zh-CN.md 展开,结合 Breadcrumb.tsxuseItemRender.tsxBreadcrumbItem.tsx 等源码,完整讲解 Breadcrumb 的 API 用法、items 数据结构、路由参数注入、下拉菜单与 browserHistory 集成、6.0.0 引入的 Semantic DOM 定制与 Design Token 主题配置。读完你将能够独立完成从基础页面层级展示到复杂路由驱动场景的面包屑搭建,并理解其底层渲染机制。

何时使用

文档明确给出了三个适用场景:

  • 当系统拥有超过两级以上的层级结构时;
  • 当需要告知用户「你在哪里」时;
  • 当需要向上导航的功能时。

从 DOM 结构看(Breadcrumb.tsx),组件最终渲染为 <nav><ol>…</ol></nav> 的语义化标签,每个条目是 <li> 元素,这对屏幕阅读器和 SEO 都是友好的结构化输出。

组件渲染原理:useItems、path 拼接与默认 itemRender

理解 Breadcrumb 的关键在于它的三条数据链路,全部可以在源码中验证:

1. items 与旧版 routes 的兼容(useItems)

useItems.ts 负责归一化输入:如果传入了 items 则直接使用;否则把旧版 routes 逐条转换为新结构——breadcrumbName 映射为 titlechildren 映射为 menu.itemsuseItems.ts)。这也是为什么文档 API 中注明 items 自 5.3.0 起推荐使用,而 Breadcrumb.Item 子组件写法在 index.tsx 中已被标记为 @deprecated。开发环境下(非 production),传入 routesBreadcrumb.Item 会触发 warning.deprecated 弃用警告(Breadcrumb.tsx),生产环境则静默兼容。

2. path 的逐级拼接与 params 替换

path 字段与 href 不同:它会把前面所有条目的 path 逐级拼接,且两者不能共用。拼接逻辑在 Breadcrumb.tsx 中:每个条目的 path 经过 getPath(params, path) 处理后 push 进 paths 数组,非末级条目的实际链接由 href = '#/${paths.join('/')} 生成。

getPath 的定义在 Breadcrumb.tsx:先去掉路径开头的 /,再用 params 对象中的键值对逐个替换路径里的 :key 占位符。同理,条目标题中的 :key 占位符由 useItemRender.tsx 中的 getBreadcrumbName 完成替换——即传入 title: ':id'params={{ id: 1 }} 时,标题渲染为 1,这就是下文「带有参数的」示例的工作原理。

3. 默认 itemRender 的 a/span 决策

未提供自定义 itemRender 时,默认渲染函数在 useItemRender.tsxrenderItem 中:只要条目能解析出 href,就渲染带 ant-breadcrumb-link 类名的 <a> 标签,否则渲染 <span>——这就是末级条目(无 href/path)不产生链接的根本原因。同时通过 pickAttrs 透传所有 data-*aria-* 属性(Breadcrumb.tsx),支持无障碍与埋点扩展。

API 全量解析

Breadcrumb

通用属性参考仓库文档中的通用属性章节(位于 docs/react 目录)。完整属性表如下:

参数 说明 类型 默认值 版本 全局配置
classNames 用于自定义组件内部各语义化结构的 class,支持对象或函数 Record<SemanticDOM, string> | (info: { props })=> Record<SemanticDOM, string> - 6.0.0 6.0.0
dropdownIcon 自定义下拉图标 ReactNode <DownOutlined /> 6.2.0 6.2.0
items 路由栈信息(>=5.3.0 推荐使用,旧版请使用 Breadcrumb.Item 子组件方式) ItemType[] - 5.3.0 ×
itemRender 自定义链接函数,和 react-router 配合使用,详见示例 (route, params, routes, paths) => ReactNode - ×
params 路由的参数 object - ×
separator 分隔符自定义 ReactNode / 6.0.0
styles 用于自定义组件内部各语义化结构的行内 style,支持对象或函数 Record<SemanticDOM, CSSProperties> | (info: { props })=> Record<SemanticDOM, CSSProperties> - 6.0.0 6.0.0

默认值的合并顺序可以在 Breadcrumb.tsx 得到印证:mergedSeparator = separator ?? contextSeparator ?? '/'mergedDropdownIcon = dropdownIcon ?? contextDropdownIcon ?? <DownOutlined />。即组件级属性优先,其次是 ConfigProviderbreadcrumb 全局配置,最后才是硬编码默认值。

ItemType

type ItemType = Omit<RouteItemType, 'title' | 'path'> | SeparatorType

源码中 ItemType 的定义为 Partial<BreadcrumbItemType & BreadcrumbSeparatorType>Breadcrumb.tsx),即每个条目既可以是普通路由项,也可以是一个分隔符项。

RouteItemType

参数 说明 类型 默认值 版本
className 自定义类名 string -
dropdownProps 弹出下拉菜单的自定义配置 Dropdown -
href 链接的目的地,不能和 path 共用 string -
path 拼接路径,每一层都会拼接前一个 path 信息。不能和 href 共用 string -
menu 菜单配置项 MenuProps - 4.24.0
onClick 单击事件 (e:MouseEvent) => void -
title 名称 ReactNode - 5.3.0

SeparatorType

const item = {
  type: 'separator', // Must have
  separator: '/',
};
参数 说明 类型 默认值 版本
type 标记为分隔符 separator 5.3.0
separator 要显示的分隔符 ReactNode / 5.3.0

分隔符渲染在 BreadcrumbSeparator.tsx:它渲染为 <li class="ant-breadcrumb-separator" aria-hidden="true">,内容为空字符串时渲染空串、为 undefined 时回退到 /aria-hidden="true" 保证了分隔符不会干扰屏幕阅读器对层级结构的朗读。

代码演示与源码印证

基本用法

对应 basic.tsxtitle 可以是纯文本,也可以是任意 ReactNode(如 <a> 标签):

import React from 'react';
import { Breadcrumb } from 'antd';

const App: React.FC = () => {
  return (
    <Breadcrumb
      items={[
        {
          title: 'Home',
        },
        {
          title: <a href="">Application Center</a>,
        },
        {
          title: <a href="">Application List</a>,
        },
        {
          title: 'An Application',
        },
      ]}
    />
  );
};

export default App;

带有图标

对应 withIcon.tsxtitle 中放入 @ant-design/icons 的图标,或图标加文字的 Fragment:

import React from 'react';
import { HomeOutlined, UserOutlined } from '@ant-design/icons';
import { Breadcrumb } from 'antd';

const App: React.FC = () => (
  <Breadcrumb
    items={[
      {
        href: '',
        title: <HomeOutlined />,
      },
      {
        href: '',
        title: (
          <>
            <UserOutlined />
            <span>Application List</span>
          </>
        ),
      },
      {
        title: 'Application',
      },
    ]}
  />
);

注意 withIcon.tsx 中还专门注释了第三方图标库(如 lucide、react-icons 渲染的裸 <svg>)的适配:图标保持居中对齐,并与文字标签保有间距——样式由 style/index.ts 中的 iconFontSize 等 token 统一控制。

带有参数

对应 withParams.tsx,演示 paramstitle 占位符的替换:

import React from 'react';
import { Breadcrumb } from 'antd';

const App: React.FC = () => (
  <Breadcrumb
    items={[
      {
        title: 'Users',
      },
      {
        title: ':id',
        href: '',
      },
    ]}
    params={{ id: 1 }}
  />
);

这里 :id 被替换为 1 的机制,正是前文 getBreadcrumbName 中用 new RegExp(:(${paramsKeys}), 'g') 做全局替换实现的(useItemRender.tsx)。

分隔符

对应 separator.tsx

<Breadcrumb
  separator=">"
  items={[
    { title: 'Home' },
    { title: 'Application Center', href: '' },
    { title: 'Application List', href: '' },
    { title: 'An Application' },
  ]}
/>

separator 可以是任意 ReactNode(图标、emoji 等),6.0.0 起还可通过 ConfigProvider 全局配置。

带下拉菜单的面包屑

对应 overlay.tsx,通过条目的 menu 属性挂载下拉:

import React from 'react';
import { Breadcrumb } from 'antd';

const menuItems = [
  {
    key: '1',
    label: <a target="_blank" rel="noopener noreferrer" href="http://www.alipay.com/">General</a>,
  },
  {
    key: '2',
    label: <a target="_blank" rel="noopener noreferrer" href="http://www.taobao.com/">Layout</a>,
  },
  {
    key: '3',
    label: <a target="_blank" rel="noopener noreferrer" href="http://www.tmall.com/">Navigation</a>,
  },
];

const App: React.FC = () => (
  <Breadcrumb
    items={[
      {
        title: 'Ant Design',
      },
      {
        title: <a href="">Component</a>,
      },
      {
        title: <a href="">General</a>,
        menu: { items: menuItems },
      },
      {
        title: 'Button',
      },
    ]}
  />
);

下拉的底层实现在 BreadcrumbItem.tsx:当条目带有 menu 时,内部用 <Dropdown placement="bottom"> 包裹条目,触发区域是 ant-breadcrumb-overlay-link 类名的 span,并附加 dropdownIcon(默认 <DownOutlined />,6.2.0 起可全局/逐组件覆盖)。menu 的其余字段(如 itemSelectIcon 等 Dropdown 的 menu 配置)会通过 dropdownProps 透传合并。

独立的分隔符

对应 separator-component.tsx,把 separator 设为空串后,用 type: 'separator' 条目在指定位置插入自定义分隔符:

<Breadcrumb
  separator=""
  items={[
    { title: 'Location' },
    { type: 'separator', separator: ':' },
    { href: '', title: 'Application Center' },
    { type: 'separator' },
    { href: '', title: 'Application List' },
    { type: 'separator' },
    { title: 'An Application' },
  ]}
/>

渲染分支在 Breadcrumb.tsxtype === 'separator' 的条目直接返回 <BreadcrumbSeparator>,跳过链接生成逻辑。

自定义语义结构的样式和类(6.0.0+)

对应 style-class.tsx。6.0.0 引入的 classNames / styles 支持三种 Semantic DOM:rootitemseparator,且均支持函数形式根据 info.props 动态返回:

import { Breadcrumb, Flex } from 'antd';
import type { BreadcrumbProps, GetProp } from 'antd';
import { createStaticStyles } from 'antd-style';

const classNames = createStaticStyles(({ css }) => ({
  root: css`
    padding: 8px;
    border-radius: 4px;
  `,
  item: css`
    color: #1890ff;
  `,
  separator: css`
    color: rgba(0, 0, 0, 0.45);
  `,
}));

const styles: BreadcrumbProps['styles'] = {
  root: { border: '1px solid #f0f0f0', padding: 8, borderRadius: 4 },
  item: { color: '#1890ff' },
  separator: { color: 'rgba(0, 0, 0, 0.45)' },
};

const stylesFn: BreadcrumbProps['styles'] = (
  info,
): GetProp<BreadcrumbProps, 'styles', 'Return'> => {
  const items = info.props.items || [];
  if (items.length > 2) {
    return {
      root: { border: '1px solid #F5EFFF', padding: 8, borderRadius: 4 },
      item: { color: '#8F87F1' },
    };
  }
  return {};
};

源码侧的支撑点有两个:一是 Breadcrumb.tsxBreadcrumbSemanticType 明确定义了 root / item / separator 三个语义槽位;二是这些合并结果通过 BreadcrumbContext.ts 下发给 InternalBreadcrumbItemBreadcrumbSeparator(见 BreadcrumbItem.tsxBreadcrumbSeparator.tsx 中对 mergedClassNames?.item / mergedStyles?.separator 的消费)。合并顺序遵循 useMergeSemantic:ConfigProvider 全局配置为低优先级,组件自身属性为高优先级。完整的语义槽位说明可参考 demo/_semantic.tsxroot(根元素,含基础文字样式与 flex 布局有序列表)、item(条目,含链接悬停、内边距等)、separator(分隔符,含外边距与颜色)的描述。

组件 Token

对应 component-token.tsx,通过 ConfigProvider 的 theme.components.Breadcrumb 覆盖 Design Token:

<ConfigProvider
  theme={{
    components: {
      Breadcrumb: {
        itemColor: '#b02121',
        lastItemColor: '#0f3a88',
        iconFontSize: 28,
        linkColor: '#979a42',
        linkHoverColor: '#9450c0',
        separatorColor: '#b41b60',
        separatorMargin: 22,
      },
    },
  }}
>
  <Breadcrumb
    separator=">"
    items={[
      { title: 'Home' },
      { title: <a href="">Application Center</a> },
      { title: <a href="">General</a>, menu: { items: menuItems } },
      { title: 'Application Center', href: '' },
    ]}
  />
</ConfigProvider>

完整的 Token 表格由文档页的动态 <ComponentTokenTable component="Breadcrumb"> 组件生成(见 index.zh-CN.md),以上示例中的 7 个 Token(itemColorlastItemColoriconFontSizelinkColorlinkHoverColorseparatorColorseparatorMargin)覆盖了文字颜色、末级条目颜色、图标字号、链接悬停色与分隔符间距等核心视觉维度,token 的实际消费实现位于 style/index.ts

和 browserHistory 配合

和 react-router 一起使用时,默认生成的 url 路径是带有 # 的(即上文源码中 #/${paths.join('/')} 的 hash 路由行为)。如果和 browserHistory 一起使用的话,你可以使用 itemRender 属性定义面包屑链接。文档给出的完整示例:

import { Link } from 'react-router';

const items = [
  {
    path: '/index',
    title: 'home',
  },
  {
    path: '/first',
    title: 'first',
    children: [
      {
        path: '/general',
        title: 'General',
      },
      {
        path: '/layout',
        title: 'Layout',
      },
      {
        path: '/navigation',
        title: 'Navigation',
      },
    ],
  },
  {
    path: '/second',
    title: 'second',
  },
];

function itemRender(currentRoute, params, items, paths) {
  const isLast = currentRoute?.path === items[items.length - 1]?.path;

  return isLast ? (
    <span>{currentRoute.title}</span>
  ) : (
    <Link to={`/${paths.join('/')}`}>{currentRoute.title}</Link>
  );
}

return <Breadcrumb itemRender={itemRender} items={items} />;

useItemRender.tsx 可以看到,只要传入了 itemRender,组件就完全交由它决定每个条目的渲染内容,四个参数依次为当前条目 route、路由参数 params、完整路由表 routes 和已拼接路径数组 paths——示例中正是利用 paths.join('/') 还原出 browserHistory 风格的路径再交给 <Link>。该行为有测试用例 tests/itemRender.test.tsx 与快照 tests/snapshots/itemRender.test.tsx.snap 覆盖,router.test.tsx 则验证了 path 逐级拼接与 params 替换的完整路由场景。

版本演进与兼容注意事项

结合源码与文档可以梳理出三条版本脉络,升级时需注意:

  1. 5.3.0:引入 items 配置式 API(含 title 字段与 type: 'separator' 分隔符项),同时 Breadcrumb.Item / Breadcrumb.Separator 子组件写法进入弃用流程——当前源码 index.tsx 中两者均标注 @deprecated,但未从导出中移除,旧代码仍可运行。
  2. 4.24.0:条目 menu 属性支持,使单个面包屑项可以承载下拉菜单。
  3. 6.0.0classNames / styles 语义化定制上线并纳入 ConfigProvider 全局配置;separator 也支持了全局配置。
  4. 6.2.0dropdownIcon 属性上线,允许替换默认的下拉指示图标。

另外注意 RouteItemTypebreadcrumbName 在 5.3.0 起被 title 取代,useItems.ts 中的 route2item 会对旧字段做自动映射,属于兼容层而非长期承诺,新代码应直接使用 title

小结

ant-design 的 Breadcrumb 以 items 数组为核心配置面:title + href/path 决定条目内容与链接生成,params 驱动 :key 占位符替换,menu + dropdownProps + dropdownIcon 提供下拉能力,itemRender 则把链接渲染的最终决定权交还给使用者以适配 react-router 等路由库。6.0.0 起,classNames/stylesroot/item/separator 三槽位语义化定制与 theme.components.Breadcrumb Design Token 共同构成了从结构到视觉的完整定制体系。所有结论均可在 components/breadcrumb 目录下的源码、demo 与 __tests__ 测试中逐一验证。

登录后查看全文
热门项目推荐
相关项目推荐