基于 React Router 的面包屑组件设计与实现
需求
在新企业版的设计中,导航栏中的面包屑需要具备以下功能:
- 显示当前页面的路径
- 面包屑节点支持显示为下拉菜单
- 面包屑节点内容可动态更改
调研
由于项目时间比较紧,调研对象仅限于几个容易找到的同类方案,最终确定的候选设计方案有两个:
- ant-design/breadcrumb: 传入 routes 路由配置对象和 itemRender 函数,根据当前路径从 routes 中匹配面包屑列表,然后用 itemRender 渲染每个面包屑节点。
- react-breadcrumbs-dynamic: 在页面中主动引入
<BreadcrumbsItem>
组件设置面包屑节点内容,然后由组件组合这些面包屑。
ant-design/breadcrumb
ant-design 的面包屑组件依赖 routes 路由配置对象,但新企业版项目并不是采用路由配置的形式集中管理路由的,如果要采用这种设计方案,那么就需要重构现有的路由代码,成本比较高。
react-breadcrumbs-dynamic
使用它需要多引入 react-through 依赖项,还得给每个页面添加 <BreadcrumbsItem>
组件。
设计
结合上述方案以及 Vue Router 的使用经验,可以设计出如下组件:
<RouterView>
:功能类似于 Vue Router 的同名组件,基于当前的路由信息渲染对应的组件<RouterBreadcrumb>
:基于当前路由信息生成面包屑<RouterBreadcrumbItem>
:动态设置面包屑结点内容<RouterStoreProvider>
: 用于实现<RouterBreadcrumbItem>
和<RouterBreadcrumb>
之间的数据通信
<RouterView>
接受的路由配置格式为:
1 | [ |
以下是完整的示例用法:
1 | import { |
这段示例代码实现了一个用户列表页面,点击列表中的 root 用户链接后,面包屑会更新为:用户 / root
。
实现
需要实现的主要功能有:
- 路由匹配
- 路由配置中的路径转换
- 动态更新面包屑结点
路由匹配
react-router 的源码目录中有个预览版的 react-router-config 包已经实现了静态路由配置的渲染支持和路由匹配,可以直接参考它的源码实现。
路由配置中的路径转换
这个功能很简单,大致的流程是递归遍历路由配置列表,然后转换每个路由配置的路径为绝对路径。
动态更新面包屑结点
<RouterStoreProvider>
组件维护一个映射表,以路由配置中的 path 为索引键,记录包括面包屑结点内容在内的状态,然后使用 React.Context 实现 <RouterBreadcrumbItem>
组件与 <RouterBreadcrumb>
组件的状态共享。
开发
新的路由方案实现起来比较简单,主要的工作量都集中在旧路由改造上,改造可以分为以下几个部分:
- 将原有的
<Switch>
+<Route>
使用方式改为<RouterView>
- 将分散在各个导航菜单、页面组件中的
<Route>
组件参数都集中到 routes 目录中,以新的路由配置表示 - 给项目和仓库页面添加
<RouterBreadcrumbItem>
组件,向面包屑注册切换菜单 - 给 PullRequest、里程碑等页面添加
<RouterBreadcrumbItem>
组件,动态更新面包屑内容
总结
由于新企业版项目采用的是全新的 React 技术栈,整个团队在 React 方面也没有积累多少开发经验,因此,在没有路由管理最佳实践方案可供使用的情况下,团队成员都是按照自己的风格管理页面的路由,随着新页面的增加以及各种新需求的实现,路由管理问题变得越来越明显,直到这次的面包屑导航组件为止,除了对它进行改造外已经没有别的办法了,因为考虑其它方案太费时间,大都会增加代码复杂度,导致代码会越改越烂。
现在采用的路由配置方案参考自 Vue Router,虽称不上是 React 路由管理的最佳实践,但也算是一个经历了众多 Vue 项目考验的成熟的方案,而且对于新企业版项目而言有以下好处:
- 路由配置的格式简单且都集中在一个目录中,易于理解和维护。
<RouterView>
组件的功能以及路由配置格式与 Vue Router 相似,有过 Vue Router 使用经验的人很容易上手。- 能作为参数传给面包屑组件使用,无需编写复杂的代码手动控制面包屑内容,以后的动态标题也能基于路由配置和匹配结果来实现。