umi 会根据pages
目录自动生成路由配置。
假设 pages
目录结构如下:
+ pages/
+ users/
- index.js
- list.js
- index.js
那么,umi 会自动生成路由配置如下:
[
{ path: '/', component: './pages/index.js' },
{ path: '/users/', component: './pages/users/index.js' },
{ path: '/users/list', component: './pages/users/list.js' },
]
umi 里约定,带 $ 前缀的目录或文件为动态路由。
比如以下目录结构:
+ pages/
+ $post/
- index.js
- comments.js
+ users/
$id.js
- index.js
会生成路由配置如下:
[
{ path: '/', component: './pages/index.js' },
{ path: '/users/:id', component: './pages/users/$id.js' },
{ path: '/:post/', component: './pages/$post/index.js' },
{ path: '/:post/comments', component: './pages/$post/comments.js' },
]
umi 里约定动态路由如果带 $ 后缀,则为可选动态路由。
比如以下结构:
+ pages/
+ users/
- $id$.js
- index.js
会生成路由配置如下:
[
{ path: '/': component: './pages/index.js' },
{ path: '/users/:id?': component: './pages/users/$id$.js' },
]
umi 里约定目录下有_layout.js
时会生成嵌套路由,以_layout.js
为该目录的 layout 。
比如以下目录结构:
+ pages/
+ users/
- _layout.js
- $id.js
- index.js
会生成路由配置如下:
[
{ path: '/users', component: './pages/users/_layout.js',
routes: [
{ path: '/users/', component: './pages/users/index.js' },
{ path: '/users/:id', component: './pages/users/$id.js' },
],
},
]
约定 src/layouts/index.js
为全局路由,返回一个 React 组件,通过 props.children 渲染子组件。
比如:
export default function(props) {
return (
<>
{ props.children }
>
);
}
你可能需要针对不同路由输出不同的全局 layout,umi 不支持这样的配置,但你仍可以在 layouts/index.js
对 location.path
做区分,渲染不同的 layout 。
比如想要针对 /login 输出简单布局,
export default function(props) {
if (props.location.pathname === '/login') {
return { props.children }
}
return (
<>
{ props.children }
>
);
}
约定 pages/404.js 为 404 页面,需返回 React 组件。
比如:
export default () => {
return (
I am a customized 404 page
);
};
注意:开发模式下,umi 会添加一个默认的 404 页面来辅助开发,但是我们仍然可通过精确地访问 /404 来验证 404 页面。
约定路由文件的首个注释如果包含 yaml 格式的配置,则会被用于扩展路由。
比如:
+ pages/
- index.js
如果 pages/index.js
里包含:
/**
* title: Index Page
* Routes:
* - ./src/routes/a.js
* - ./src/routes/b.js
*/
则会生成路由配置:
[
{ path: '/', component: './index.js',
title: 'Index Page',
Routes: [ './src/routes/a.js', './src/routes/b.js' ],
},
]
如果你倾向于使用配置式的路由,可以配置.umirc.(ts|js)
或者 config/config.(ts|js)
配置文件中的 routes 属性,此配置项存在时则不会对 src/pages
目录做约定式的解析。
比如:
export default {
routes: [
{ path: '/', component: './a' },
{ path: '/list', component: './b', Routes: ['./routes/PrivateRoute.js'] },
{ path: '/users', component: './users/_layout',
routes: [
{ path: '/users/detail', component: './users/detail' },
{ path: '/users/:id', component: './users/id' }
]
},
],
};
注意:
component 是相对于 src/pages
目录的
umi 的权限路由是通过配置路由的 Routes 属性来实现。约定式的通过 yaml 注释添加,配置式的直接配上即可。
比如有以下配置:
[
{ path: '/', component: './pages/index.js' },
{ path: '/list', component: './pages/list.js', Routes: ['./routes/PrivateRoute.js'] },
]
然后 umi 会用 ./routes/PrivateRoute.js
来渲染 /list。
./routes/PrivateRoute.js
文件示例:
export default (props) => {
return (
PrivateRoute (routes/PrivateRoute.js)
{ props.children }
);
}
路由动效应该是有多种实现方式,这里举 react-transition-group
的例子。
先安装依赖,
$ yarn add react-transition-group
在 layout 组件(layouts/index.js
或者 pages 子目录下的 _layout.js
)里在渲染子组件时用 TransitionGroup 和 CSSTransition 包裹一层,并以location.pathname
为 key,
import withRouter from 'umi/withRouter';
import { TransitionGroup, CSSTransition } from "react-transition-group";
export default withRouter(
({ location }) =>
{ children }
)
上面用到的 fade 样式,可以在 src 下的 global.css 里定义:
.fade-enter {
opacity: 0;
z-index: 1;
}
.fade-enter.fade-enter-active {
opacity: 1;
transition: opacity 250ms ease-in;
}
面包屑也是有多种实现方式,这里举 react-router-breadcrumbs-hoc
的例子。
先安装依赖,
$ yarn add react-router-breadcrumbs-hoc
然后实现一个 Breakcrumbs.js,比如:
import NavLink from 'umi/navlink';
import withBreadcrumbs from 'react-router-breadcrumbs-hoc';
// 更多配置请移步 https://github.com/icd2k3/react-router-breadcrumbs-hoc
const routes = [
{ path: '/', breadcrumb: '首页' },
{ path: '/list', breadcrumb: 'List Page' },
];
export default withBreadcrumbs(routes)(({ breadcrumbs }) => (
{breadcrumbs.map((breadcrumb, index) => (
{breadcrumb}
{(index < breadcrumbs.length - 1) && / }
))}
));
然后在需要的地方引入此 React 组件即可。
umi 默认是用的 Browser History,如果要用 Hash History,需配置:
export default {
history: 'hash',
}
在 layout 组件(layouts/index.js
或者 pages 子目录下的 _layout.js
)的 componentDidUpdate 里决定是否 scroll to top,比如:
import { Component } from 'react';
import withRouter from 'umi/withRouter';
class Layout extends Component {
componentDidUpdate(prevProps) {
if (this.props.location !== prevProps.location) {
window.scrollTo(0, 0);
}
}
render() {
return this.props.children;
}
}
export default withRouter(Layout);