写在前面
最近在学习React,并且开发一个类似于后台管理功能的前端项目,UI用的是阿里的ant design。在后台管理的项目中,其中一个比较实用的功能是多标签的模式,即点击不同菜单可以打开多个不同的Tab,并且点击Tab可以切换不同的页面内容,页面总体布局如下图:
在传统的jsp开发的年代,比较流行的一种多标签页的实现方式是用 iframe 实现多标签功能,不过由于iframe有着性能以及兼容性问题,网页上嵌套iframe的用法逐渐被抛弃。基于以上原因,项目中采用react router和antd组件的方式实现多标签功能。
具体实现
路由配置
项目中有两个主要组件,Login对应的是登录页面,Main对应的是主页面(即登录成功后跳转的页面),另外其他组件为具体的业务组件。在App.tsx中配置以下路由:
<Provider store={store}>
<HashRouter>
<Switch>
<Route path='/login' component={Login} ></Route>
<Route exact={false} path='/' component={Main} ></Route>
</Switch>
</HashRouter>
</Provider>
Login的配置比较简单,对应的路由是/login
,即在访问/login
时,显示login组件。
Main的路由中配置的路径为/
,并且加了exact={false}
的属性配置,即访问所有/
路径下的子路径(当然除了/login
),都会匹配至Main组件。
按以上路由配置时,实际实现的效果是访问/login
,显示Login组件,访问/a
,显示Main组件,访问/b
,还是显示Main组件,另外访问除了/login
地址之外的其他任何地址,都是显示Main组件,但是此时地址栏里的地址确实发生变化。
多Tabs标签页实现逻辑
实现逻辑比较简单:用户点击子菜单,首先需要做的是判断打开的tab中有无该菜单页面,有的话显示该tab,没有则添加tab并显示该新tab内容,tab功能比较简单,使用antd的Tabs标签页组件即可(Tabs标签页)。
而此时我们需要做的就是在Main组件中监控路由变化,并根据路由显示出具体的组件即可。
监听路由
React路由history对象提供了一个listen接口,文档如下:
export interface History<HistoryLocationState = LocationState> {
length: number;
action: Action;
location: Location<HistoryLocationState>;
push(path: Path, state?: HistoryLocationState): void;
push(location: LocationDescriptor<HistoryLocationState>): void;
replace(path: Path, state?: HistoryLocationState): void;
replace(location: LocationDescriptor<HistoryLocationState>): void;
go(n: number): void;
goBack(): void;
goForward(): void;
block(prompt?: boolean | string | TransitionPromptHook<HistoryLocationState>): UnregisterCallback;
listen(listener: LocationListener<HistoryLocationState>): UnregisterCallback;
createHref(location: LocationDescriptorObject<HistoryLocationState>): Href;
}
listen接口参数listener监听方法参数中,其中一个参数为location,其中包含了访问路由地址等信息。listen监听方法中核心实现代码如下:
this.props.history.listen((location, action) => {
let {pathname} = location;
const existFlag = this.props.tabs.findIndex((item: RouteDef) => item.path === pathname) >= 0;
if (!existFlag) {
// 添加tab,并显示tab组件内容
} else {
// 显示已存在的tab组件内容
}
});
另外需要特别考虑的一点就是如果访问的url对应的业务组件不存在,需要显示404页面,在此不展开来讲。
至此多标签功能基本上已完成。