在后盾我的项目中应用tabs导航是一个重要的性能
上面介绍一下如果配合umi框架和对应的插件实现此性能
参考:react-activation
参考实现:实现一个tabs
目前我的项目用的架构设计是umi3+react17+antd pro5
1.引入应用相干插件
插件地址: umi-plugin-keep-alive
npm install umi-plugin-keep-alive --save# oryarn add umi-plugin-keep-alive
2.公共组件封装
components文件夹下创立KeepAvlieTabs
对应的less款式请自行批改本人的需要
相干的keepAlive与生命周期应用计划及问题请到上述链接react-activation查看
创立index.tsx文件
// /components/KeepAvlieTabs/index.tsximport { useAliveController } from 'react-activation';import { arrayDeduplicate } from '@/utils/Array';import type { CachingNode } from './type';import Tab from './Tab';import styles from './index.less';import { useHistory, useLocation } from 'umi';export default function KeepAliveTabs() { // history导航 const history = useHistory(); // 本地路由信息 const location = useLocation(); // 获取缓存节点办法和信息 const { getCachingNodes } = useAliveController(); const cachingNodes: CachingNode[] = getCachingNodes(); // 因为是异步组件,须要在这儿解决一下缓存中的反复问题 let nodes: CachingNode[] = arrayDeduplicate(cachingNodes, 'path'); // 首页不参加tabs切换的敞开操作 nodes = nodes.filter((item) => item.path !== '/home'); return ( <ul className={styles['alive-tabs']}> <li className={location.pathname === '/home' ? styles.home_active : styles.home_deactive} onClick={() => { history.push('/home'); }} > <div className="tags-nav"> <span>首页</span> </div> </li> {nodes.map((node) => ( <Tab key={node!.id} node={node} /> ))} </ul> );}
创立Tab.tsx文件
// /components/KeepAvlieTabs/Tab.tsximport { useHistory, useLocation } from 'umi';import { useAliveController } from 'react-activation';import { CloseCircleOutlined } from '@ant-design/icons';import type { CachingNode } from './type';import styles from './index.less';export default function Tab({ node }: { node: CachingNode }) { const history = useHistory(); const location = useLocation(); // 同上,dropScope是开释节点,点删除后删掉以后节点信息 const { getCachingNodes, dropScope } = useAliveController(); const cachingNodes: CachingNode[] | any[] = getCachingNodes(); // 执行tab的删除操作 function dropTab(e: React.MouseEvent<HTMLButtonElement>) { e.stopPropagation(); // 如果敞开激活中的 KeepAlive Tab,须要先来到以后路由 // 触发 KeepAlive unactivated 后再进行 drop if (location.pathname === node.path) { // 路由异步加载管制 const unlisten = history.listen(() => { setTimeout(() => { dropScope(node.name as string | RegExp); }, 30); }); unlisten(); // 返回排除以后 node 后的最初一个 tab if (cachingNodes.length <= 1) { history.push('/'); } else { const { path } = cachingNodes.filter((item) => item.path !== node.path).pop(); history.push(path); } } else { dropScope(node.name as string | RegExp); } } // 设置以后tab的款式 const className = () => { if (location.pathname === node.path) { if (location.pathname === '/home') { return `${styles.active} ${styles.home_active}`; } return `${styles.active}`; } return `${styles.deactive}`; }; return ( <li className={className()} onClick={() => { history.push(node.path); }} > <div className="tags-nav"> <span>{node.name}</span> {<CloseCircleOutlined className={styles['close-btn']} onClick={dropTab} />} </div> </li> );}
创立类型文件type.ts
export type CachingNode = { createTime: number; updateTime: number; name?: string; id: string; [key: string]: any;};
创立款式less文件
.alive-tabs { height: 100%; margin: 0; padding: 0; overflow: hidden; white-space: nowrap; background: #fff; li { position: relative; display: inline-block; padding: 0 28px 0 10px; line-height: 32px; vertical-align: top; list-style: none; border-right: solid 1px #e6e6e6; cursor: pointer; transition: background 0.2s; } .active { height: 32px; background: rgba(#1890ff, 0.1); border-bottom: 2px solid #1890ff; // background-color: #42b983; } .home_active { height: 32px; padding: 0 10px; background: rgba(#1890ff, 0.1); border-bottom: 2px solid #1890ff; // background-color: #42b983; } .home_deactive { padding: 0 10px; } .deactive { background: #fff; } .close-btn { position: absolute; top: 11px; right: 10px; display: flex; align-items: center; justify-content: center; font-size: 12px; line-height: 0; outline: none; // transform: translateY(-50%); }}
3.在组件中应用keepAlive
创立Books/index.tsx
import React from 'react';import { KeepAlive, useActivate, useUnactivate } from 'react-activation';const Books: React.FC = () => { return <div>我是被缓存的组件</div>;};export default (props: any) => { useActivate(()=>{ console.log("我被激活了"); }) useUnactivate(()=>{ console.log("我被缓存了"); }) // 上面应用这样的形式去管制路由操作 // 是为了同步显示路由定义中的title和匹配路由path做对应的操作 // 可依据自行需要批改以后的逻辑 return ( <KeepAlive name={props.route.name} path={props.route.path} saveScrollPosition="screen"> <Books /> </KeepAlive> );};
4.keepAliveTabs挂载到界面上
咱们的页面布局左高低构造,在app.tsx中,挂载到咱们的头部中,超出显示滚动条,具体的款式和性能请自行添加
未实现鼠标右键菜单敞开所有,左右切换,请自行添加,antd有相干的组件
export const layout: RunTimeLayoutConfig = ({ initialState }: any) => { return { // 管制组件是否可缓存 disableMobile: true, headerContentRender: () => <KeepAliveTabs />, ... };};