Bread 面包屑
- 定义面包屑list,每次push当前页面,push前校验是否为第一层级,第一层级清除list
- 单页面路由需监听页面刷新,缓存list
import React, { useContext, useEffect, useState } from 'react';
import classNames from 'classnames';
import { withRouter } from 'react-router-dom';
import { useLastLocation } from 'react-router-last-location';
import { findIndex } from 'lodash';
import { Breadcrumb } from '@huohua/luca';
import NativePageJump from '@utils/nativePageJump';
import RouterContext from '@components/Context/RouterContext';
import './style.less';
// 历史记录
let PRE_LIST = [];
// 通过name找到记录
const getBreadcrumbName = ({ routes, location }) => {
return routes.filter(f => {
// 存在动态参数
if (
f?.action?.indexOf(':') !== -1 &&
f?.action?.split('/')?.length === location?.pathname?.split('/')?.length &&
location?.pathname?.startsWith(f?.action?.split(':')?.[0])
) {
return f;
}
return f?.action === location?.pathname;
})?.[0];
};
// 获取面包屑记录
function getBreadcrumb({ routes, location, cache, rootPages }) {
if (location) {
const cacheUrl = `${location?.pathname}${location?.search}`;
const route = getBreadcrumbName({ routes, location });
// 如果当前是二级目录,需要将一级目录手动导入
if (rootPages?.find(item => item?.id === route?.id)) {
const parent = routes?.find(item => item.id === route?.pid);
parent &&
cache.push({
path: parent?.action,
name: parent?.title,
});
}
cache.push({
path: cacheUrl,
name: route?.title,
});
return cache;
}
return [];
}
interface BreadRoutes {
name: string;
path: string;
}
/**
* 面包屑
* @constructor
* 面包屑list 历史路由 + 当前路由
* 需鉴定页面刷新,存储历史路由
* 根目录判断依托于星云菜单配置 二级菜单为页面跳转
* todo 一级目录 未对应直接页面,点击不可跳转 pid为0
* 二级目录 为第一层页面
*/
const Bread = ({ routes, location }) => {
// 获取最后一个地址 - 上个页面地址
const lastLocation: any = useLastLocation();
const router: any = useContext(RouterContext);
// 二级目录
const [rootPages, setRootPages] = useState<any[]>([]);
// 面包屑记录
const [breadRoutes, setBreadRouts] = useState<BreadRoutes[]>([]);
useEffect(() => {
if (!routes?.length) return;
// 二级目录
const packageRoute = routes?.filter(item => item?.pid === 0 && item?.display);
// 根目录 -- 星云返回的二级目录
let _rootPages = [];
packageRoute?.map(item => {
const list = routes?.filter(it => it?.pid === item?.id);
_rootPages = _rootPages.concat(list);
});
setRootPages(_rootPages);
}, [routes]);
// 监听事件处理
const listenReload = () => {
// 设置刷新字段
window.sessionStorage.setItem('BREAD_PAGE_LOAD', '1');
// 存储历史记录(不包含当前页面)
if (PRE_LIST?.length) {
window.sessionStorage.setItem('BREAD_PRE_LIST', JSON.stringify(PRE_LIST));
}
};
// 监听页面刷新
useEffect(() => {
const isReload = window.sessionStorage.getItem('BREAD_PAGE_LOAD');
if (!isReload) window.sessionStorage.setItem('BREAD_PAGE_LOAD', '0');
window.addEventListener('beforeunload', listenReload);
return () => {
window.removeEventListener('beforeunload', listenReload);
};
}, []);
// 跳转地址
useEffect(() => {
if (!routes?.length || !rootPages?.length || !location) return;
// 当前页面是否刷新
const isReload = window.sessionStorage.getItem('BREAD_PAGE_LOAD');
if (!PRE_LIST?.length && isReload === '1') {
// 历史页面
PRE_LIST = JSON.parse(window.sessionStorage.getItem('BREAD_PRE_LIST') || '[]');
window.sessionStorage.setItem('BREAD_PAGE_LOAD', '0');
} else {
// 不刷新 --> PRE_LIST 为上个页面之前的历史,需要通过 lastLocation 合成为历史数据
PRE_LIST = getBreadcrumb({ routes, location: lastLocation, cache: PRE_LIST, rootPages });
}
// 当前页面
let current = [];
// 二级导航清空数据, 并导入一级导航
if (rootPages?.find(item => item?.action === location?.pathname)) {
PRE_LIST = [];
}
// 当前路由
current = getBreadcrumb({ routes, location, cache: current, rootPages });
// 面包屑
const result = [...PRE_LIST, ...current];
// 查找与当前路径相同的第一个路由 并将其从面包屑中去除
const index = findIndex(result || [], {
name: getBreadcrumbName({ routes, location })?.title,
});
index !== result.length - 1 && result.splice(index + 1, result.length);
setBreadRouts(() => result);
}, [location, routes, lastLocation, rootPages]);
if (breadRoutes.length === 0) return null;
const handleJumpPage = url => {
NativePageJump(
{
url,
router,
},
{
isReplace: true,
},
);
};
return (
<Breadcrumb className="bread-crumb" separator=">">
{breadRoutes.map((c, index) => {
return (
<Breadcrumb.Item
className={classNames('crumb', { 'last-crumb': index === breadRoutes?.length - 1 })}
key={`breadcrumb-${index}`}
// 一级目录、当前页皆不可点击跳转
onClick={() => index !== breadRoutes?.length - 1 && index !== 0 && handleJumpPage(c.path)}>
{c?.name}
</Breadcrumb.Item>
);
})}
</Breadcrumb>
);
};
// 导出
export default withRouter(Bread);
学习
为了更方便记录typeScript知识点,才创建了这个专栏,仅供个人学习使用~
278 声望
15 粉丝
推荐阅读
用了那么久的 SVG,你还没有入门吗?
其实在大部分的项目中都有 直接 或 间接 使用到 SVG 和 Canvas,但是在大多数时候我们只是选择 简单了解 或 直接跳过,这有问题吗?没有问题,毕竟砖还是要搬的!
熊的猫赞 17阅读 1.6k评论 2
你可能需要的多文档页面交互方案
在日常工作中,面对不同的需求场景,你可能会遇到需要进行多文档页面间交互的实现,例如在 A 页面跳转到 B 页面进行某些操作后,A 页面需要针对该操作做出一定的反馈等等,这个看似简单的功能,却也需要根据不同...
熊的猫赞 8阅读 1.3k
把React新文档投喂给 GPT-4 后...
大家好,我卡颂。最近,React新文档终于上线了。从内容上看,新文档包括:理论知识、学习指引API介绍从形式上看,新文档除了传统的文字内容,还包括:在线Demo示意图小测验可以说是阅读体验拉满。但是,由于文档...
卡颂赞 7阅读 7.6k评论 3
第九期:前端九条启发分享
下图是一个常见的列表, 点击列表里的详情按钮会跳到详情页, 那么也许我们在详情页修改了数据状态, 此时可能需要把修改后的状态直接传给列表页从而本地直接更新列表, 这样就不用发送新的api请求与后端交互了。
lulu_up赞 8阅读 868
Next.js-集成状态管理器共享access token以及刷新access token解决方案
SSR和SPA最大的区别就是SSR会区分客户端Client和服务端Server,并且SSR之间只能通过cookie才能在Client和Server之间通信,例如:token信息,以往我们在SPA项目中是使用localStorage或者sessionStorage来存储,但...
Awbeci赞 4阅读 9.1k评论 2
不数不知道,React已经有22个hook了
大家好,我卡颂。5月30日刚好是React10周年纪念日。我顺手拉了下React最新代码,这一看不要紧,居然已经有22个hook了。其中:react包导出了21个react-dom包导出了1个(useFormStatus)本文会从React这些年发展脉...
卡颂赞 6阅读 627
Rollup 基本概念及使用
Rollup是一款基于ESModule模块规范实现的JavaScript打包工具,在前端社区中赫赫有名,同时也在Vite的架构体系中发挥着重要作用。不仅是Vite生产环境下的打包工具,其插件机制也被Vite所兼容,可以说是Vite的构建...
xiangzhihong赞 3阅读 861
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。