一、初次上手
最开始在 demo 中写路由的时候,是这样的:
// container/index.js
class App extends Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
return (
<HashRouter basename="/" >
<div id="nav">
<Sider />
<div id="rightWrap">
<Menu mode="horizontal">
<SubMenu title={<span><Icon type="user" />{this.state.username}</span>}>
<Menu.Item key="setting:1">退出</Menu.Item>
</SubMenu>
</Menu>
<div className="right-box">
<Switch>
<Route path="/" exact render={() => <h1>Home Page</h1>} />
<Route path="/page1" exact component={UserList}></Route>
<Route path="/page2" exact component={PostList}></Route>
<Route path="/page3" exact render={() => <h1>路由测试</h1>}></Route>
<Route path="/page4" exact render={() => <h1>路由测试</h1>}></Route>
<Redirect to="/" />
</Switch>
</div>
</div>
</div>
</HashRouter>
);
}
}
// sider/index.jsx
class Sider extends Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
return (
<div id="leftMenu">
<span className="logo" style={{marginLeft: '40px'}}>主菜单</span>
<Menu theme="dark"
style={{ width: 200 }}
defaultOpenKeys={['sub1', 'sub2']}
defaultSelectedKeys={[this.state.current]}
mode="inline"
>
<SubMenu key="sub1" title={<span><Icon type="bars" /><span>子菜单</span></span>}>
<Menu.Item key="1"><Link to="/page1">用redux-thunk获取数据</Link></Menu.Item>
<Menu.Item key="2"><Link to="/page2">用redux-saga获取数据</Link></Menu.Item>
<Menu.Item key="3"><Link to="/users">测试路由</Link></Menu.Item>
<Menu.Item key="4"><Link to="/page4" >测试路由</Link></Menu.Item>
</SubMenu>
</Menu>
</div>
);
}
}
可以看到,路由散布在两个文件中,意味着每次更改路由的时候,都需要更改两个地方,而且还得去找这两个文件在哪,可能有时候修改了一个地方,然后运行之后点击的时候报错了,再去修改另一个地方,这样是很浪费时间的。
因此,如果能把路由的配置抽出来进行集中式的路由管理,每次修改只需在那一个地方对路由进行修改,是很值得考虑的。
二、集中管理路由
通过路由配置来生成路由的方式是参考了 Material-UI Theme 模板中的写法。 尽管在使用这个 UI 框架时,让我很抓狂,但是有些地方还是值得学习的。┐( ̄ヮ ̄)┌
(1)路由 config
const dashRoutes = [
{
path: '/home',
name: '主菜单',
component: () => <h1>Home Page</h1>
},
{
collapse: true,
name: 'Nav One',
key: 'sub1',
icon: <Icon type="mail" />,
children: [
{
path: '/userList',
name: '用户列表',
key: 1,
icon: '',
component: UserList
},
{
path: '/postList',
name: '帖子列表',
key: 2,
icon: '',
component: PostList
},
{
path: '/option3',
name: 'Option3',
key: 3,
icon: '',
component: () => <h1>Option3</h1>
},
{
collapse: true,
name: 'Submenu',
key: 'submenu',
icon: '',
children: [
{
path: '/option4',
name: 'Option4',
key: 4,
icon: '',
component: () => <h1>Option4</h1>
},
{
path: '/option5',
name: 'Option5',
key: 5,
icon: '',
component: () => <h1>Option5</h1>
}
]
}
]
},
{
collapse: true,
name: 'Nav Two',
key: 'sub2',
icon: <Icon type="appstore" />,
children: [
{
path: '/Option6',
name: 'Option6',
key: 6,
icon: '',
component: () => <h1>Option6</h1>
},
]
},
{ redirect: true, path: '/', to: '/home', name: '' }
];
(2)根据 config 生成路由
const switchRoutes = (
<Switch>
{dashRoutes.map((prop, key) => {
if (prop.redirect) {
return <Redirect from={prop.path} to={prop.to} key={key} />;
}
if (prop.collapse) {
return prop.children.map((prop, key) => {
if (prop.collapse) {
return prop.children.map((prop, key) => {
return <Route path={prop.path} component={prop.component} key={key} />;
})
}
return <Route path={prop.path} component={prop.component} key={key} />;
});
}
return <Route path={prop.path} component={prop.component} key={key} />;
})}
</Switch>
);
(3)生成左侧菜单
<Menu theme="dark"
style={{ width: 200 }}
defaultOpenKeys={['sub1', 'sub2']}
defaultSelectedKeys={[this.state.current]}
mode="inline"
>
{routes.map((prop, index) => {
if (prop.redirect) return;
if (prop.collapse) {
return (
<SubMenu key={prop.key} title={<span>{prop.icon}<span>{prop.name}</span></span>}>
{prop.children.map((prop, index) => {
if (prop.children) {
return (
<SubMenu key={prop.key} title={<span>{prop.name}</span>}>
{prop.children.map((prop, index) => {
return <Menu.Item key={prop.key}><Link to={prop.path}>{prop.name}</Link></Menu.Item>;
})}
</SubMenu>
)
}
return <Menu.Item key={prop.key}><Link to={prop.path}>{prop.name}</Link></Menu.Item>;
})}
</SubMenu>
)
}
})}
</Menu>
现在只需要在路由配置文件中进行统一的路由修改,模块引入,修改 icon 就可以了。
ps:每个项目的左侧菜单不一样,需要根据实际情况调整代码,本文只是利用 antd 的 Menu 组件举个示例。
👉 DEMO(check branch:webpack4+router4)