1
0
Fork 0
Obsidian 管理的个人笔记仓库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

2.9 KiB

最近在写基于 React 和 Antd 的后台管理系统,用作我的博客管理上,在参考其他开源项目的时候有一个功能我很感兴趣,就是在管理后台中加入一个像浏览器 Tabs 标签页的功能,让它实现切换标签页的功能,虽然现在的管理系统的页面总数不多其实没有什么快速切换的需求 = = 刚看到这个问题的时候,我的第一反应是有没有一个 API 可以记录并获取路由栈中的所有路由,再把他们给渲染出来,就能实现标签页的显示问题了,但是我找了一下好像没有这样的 API,所有后面会用 Context + useEffect 手写记录路由的方式来实现标签页的显示,要是有谁知道有这样一个API可以告诉我哇

大致的思路

外层用 Context 包裹,在 Context 内部用 useEffect 监听路由是否发生变化,也就是 pathname,如果发生了变化就记录路由的属性,因为要实现显示Tab名称、Tab 跳转和保存路由的查询参数,所以记录的时候这些信息要一起保存起来。 其实这个功能是可以不用 Context 实现,在 Tabs 组件内部使用 useEffect 也能实现相同的功能,但是我考虑到后边管理后台中或许会有别的页面也会需要用到类似的功能,就把它抽离出来方便复用。

Tabs 添加路由

有思路之后实现起来就很容易了,首先要实现一个 Context ,这个很简单直接跳过,然后实现一个路由的监听记录函数,这里用 useEffect 来做,具体的逻辑可以看函数的注释

// react-router 的 useLocation Hook
const { pathname, search } = useLocation();
// useEffect 监听路由是否发生变化
useEffect(() => addTabItem(pathname, search), [pathname, search]);

// 记录路由的 State,Tab列表
const [tabList, setTabList] = useState(
	[{ name: "Dashboard", path: "/", search: "" }]
);

// 路由添加函数
const addTabItem = (path, search) => {
	// 判断路由是不是已经存在于 State 中,不存在就添加到 Tab 列表中
	if (tabList.findIndex((item) => item.path === path) === -1) {
		// 这里主要是为了保存 Tab 对应的路由名称,flattenArray 是数组扁平化函数
		// 由于我的路由是用 useRoutes 实现的约定式路由,路由的名称也记录在里边
		// 所以这里需要将其扁平化和找到对应的路由名称
		const flattenList = flattenArray(routerConfig);
		const routerIndex = flattenList.findIndex((item) => {
			item.path === path
		});

		// 最后将其一起保存在 Tab 列表中
		if (routerIndex !== -1) {
			setTabList([
				...tabList,
				{ path, name: flattenList[routerIndex].name, search },
			]);
		}
	}

	// 存在就切换路由,后面会写到
	switchTab(path, search);
};

以上的逻辑就是最核心的部分,通过监听路由变化,我们得到了一个 Tabs 列表,后续只需要渲染出它显示的问题就解决了

Tabs 切换路由和关闭路由