本文阐述了如何在一个使用了 react-router 的 react 项目中合理的使用 antd-mobile tabbar 功能。在 antd-mobile 官方的例子中可以看到,只需要将不同的组件放置到每个 TabBar.Item 里面就可以了,这样就可以实现简单的切换效果,但是存在几个问题。 一个是切换过程中,路由是不会跟着切换的。比如我们想分享一个地址,当其他人打开这个地址时自动就跳转到第二个 tab 上。如果按上面的方法做是无法实现的。 另外一个问题是这样的设计不太符合大型项目的框架设计,我们往往会制作一些 layouts,给不同的组件匹配不同的 layout。如果按上面介绍的方法做,也是不好实现的。 综合以上两点问题,再加上 Google 了一些资料后,写下本文,以帮助更多遇到类似问题的人。

解决方案

首先定义四个路由分别指定不同的 component,要注意的是这四个路由都统一使用一个 layout,这也就解决了一些大型项目中分多种 layout 的问题。如下代码所示:

1
2
3
4
5
6
7
8
9
10
11
<Router history={browserHistory}>
{/* MainLayout 中包含了 antd-mobile tabbar */}
<Route path='/' component={MainLayout}>
{/* 默认跳转到 questions 页面 */}
<IndexRedirect to='/questions' />
<Route path='/questions' component={Questions} />
<Route path='/activities' component={Activities} />
<Route path='/videos' component={Videos} />
<Route path='/mine' component={Mine} />
</Route>
</Router>

随后我们看一下 mainLayout 的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
const MainLayout = ({children}) => {
const pathname = children.props.location.pathname

return (
<TabBar
unselectedTintColor='#949494'
tintColor='#33A3F4'
barTintColor='white'
>
<TabBar.Item
title='问答'
key='questions'
icon={<div className='questions-icon' />}
selectedIcon={<div className='questions-selected-icon' />}
selected={pathname === '/questions'}
onPress={() => {
browserHistory.push('/questions')
}}
>
{ pathname === '/questions' ? children : null }
</TabBar.Item>
<TabBar.Item
title='活动'
key='activities'
icon={<div className='activities-icon' />}
selectedIcon={<div className='activities-selected-icon' />}
selected={pathname === '/activities'}
onPress={() => {
browserHistory.push('/activities')
}}
>
{ pathname === '/activities' ? children : null }
</TabBar.Item>
<TabBar.Item
title='视频'
key='videos'
icon={<div className='videos-icon' />}
selectedIcon={<div className='videos-selected-icon' />}
selected={pathname === '/videos'}
onPress={() => {
browserHistory.push('/videos')
}}
>
{ pathname === '/videos' ? children : null }
</TabBar.Item>
<TabBar.Item
title='我的'
key='mine'
icon={<div className='mine-icon' />}
selectedIcon={<div className='mine-selected-icon' />}
selected={pathname === '/mine'}
onPress={() => {
browserHistory.push('/mine')
}}
>
{ pathname === '/mine' ? children : null }
</TabBar.Item>
</TabBar>
)
}

这里重点的代码就是 pathname === '/questions' ? children : null,根据当前路由判断加载不同的 component,并且在点击任何一个按钮的时候,自动跳转到指定的路由上。其中 selected 属性也根据路由动态的变换样式。路由传递给 mainLayout 是一个 children,这个 children 中就包含了组件的信息,我们根据路由的不同加载即可。

总结

这样处理后无论我们直接访问 URL 还是点击 tabbar 下面的任意按钮,不但可以切换页面,路由也会随之变动。最重要的是我们套用了 layout,让项目看起来更加合理。