UMI是蚂蚁金服的底层前端框架,也是一个基于React的企业级前端应用框架,它提供了开箱即用的项目脚手架和插件化的配置,如路由构建、部署测试、文档工具、请求库等,帮助开发者快速搭建和管理复杂的前端项目,其设计目标是提高前端项目的开发效率和可维护性,尤其适用于大型复杂项目的开发与管理。
路由不仅仅是页面之间导航的枢纽,它还负责管理应用的状态、控制用户体验的流畅性,以及支持深度链接和数据预取等关键功能。在React生态系统中,umi框架以其强大的路由管理能力脱颖而出,为开发者提供了一种灵活且高效的方式来构建现代单页应用,本文将揭示umi路由的精髓,并为项目中的路由设计提供深刻的启发和实用的指导。
目录
约定式路由
约定式路由就是不需要再去写路由表而是直接创建组件,umi底层会根据开发者创建的组件从而在内部生产路由表,比如我们在pages文件中创建如下几个tsx文件:
umi底层会自动给我们创建好路由表,从而不需要在手动去写路由表的内容:
这里我们可以做一个菜单导航进行一个路由的跳转,如下这里我们使用一个styled-components库进行一个样式操作,不了解styled-components推荐参考这篇文章:地址 ,我们在布局文件layout中进行如下操作:
import { NavLink, Outlet } from "umi";
import styled from "styled-components";
const StyleLayoutBox = styled.div`
width: 100%;
height: 20px;
padding-bottom: 20px;
border-bottom: 1px solid red;
a {
margin-right: 10px;
color: #000;
text-decoration: none;
font-size: 20px;
&.active {
color: red;
}
}
.container {
margin: 20px auto;
}
`
// 在 jsx 中使用
export default function App() {
return (
<StyleLayoutBox>
<NavLink to="/">主页</NavLink>
<NavLink to="/count">计数器</NavLink>
<NavLink to="/user">个人中心</NavLink>
<div className="container">
<Outlet></Outlet>
</div>
</StyleLayoutBox>
);
}
最终呈现的效果如下所示:
当然这里我们可以配置一下我们的二级路由,这里我们可以在一级路由的页面中设置一下二级路由的跳转路径,具体代码如下所示:
// 个人中心
import { NavLink, Outlet } from "umi";
import styled from "styled-components";
const StyleUserBox = styled.div`
width: 100%;
height: 30px;
border-bottom: 1px solid #ccc;
padding-bottom: 10px;
a {
margin-right: 20px;
&.active {
color: #007bff;
}
}
.container {
margin-top: 20px;
}
`
const PersonalPage = () => {
return (
<StyleUserBox>
<NavLink to="/user/order">订单管理</NavLink>
<NavLink to="/user/profile">个人中心</NavLink>
<div className="container">
<Outlet></Outlet>
</div>
</StyleUserBox>
)
};
export default PersonalPage;
页面呈现的效果如下所示:
可以看到从始至终,我们都没有创建任何的路由表,每一个组件默认都实现了懒加载,不需要开发者进行任何的配置,具体如下所示:
配置式路由
配置式路由需要在配置文件编写相应的路由表,在.umirc.ts文件或者config文件夹下创建routes.ts都是可以的,这里我们就先在config/routes.ts文件中创建路由表即可:
const routes: any[] = [
{
path: '/',
component: 'index',
title: '首页'
},
{
path: '/count',
component: 'count',
title: '计数器'
},
{
path: '/user',
component: 'user',
title: '用户',
routes: [
// 重定向
{
path: '/user',
redirect: '/user/order',
},
{
path: '/user/order',
component: 'user/order',
title: '我的订单'
},
{
path: '/user/profile',
component: 'user/profile',
title: '个人信息'
}
]
},
{
path: '*',
component: '404',
title: '404'
}
]
export default routes
然后我们在config.ts文件中配置一下全局的配置:
import { defineConfig } from "umi";
import routes from './config.routes'
export default defineConfig({
// 配置式路由
npmClient: 'pnpm',
routes,
});
最终呈现的效果如下所示:
当然这里我们也可以使用全局的loading组件来实现网速缓慢时的loading加载效果,这里借助antd中的一个loading组件来实现:
import { Spin } from "antd";
export default () => {
return <div>
<Spin size="large"></Spin>
</div>;
};
效果如下所示:
路由跳转传参
在UMI中的路由跳转是分为两类的,如下:
声明式导航:Link / NavLink;
编程式导航:history对象 / useNavigate => navigate()
history:这里我们需要借助umi中提供的history进行编程式路由导航,具体代码如下:
const OrderPage = () => {
// 创建navigate对象
const navigate = useNavigate();
return (
<div>
<h1>我的订单</h1>
<Button type="primary" onClick={()=> {
// history.push('/user/profile');
// 问号传参
// history.push({
// pathname: '/user/profile',
// search: '?name=zhangsan&age=18'
// })
// 隐式传参, 在目标组件刷新后,参数不会丢失
// history.push("/user/profile", {
// name: 'zhangsan',
// age: '18'
// })
// 需要在config.ts或者.unirc.ts中配置historyWithQuery选项之后,才能通过query进行传参
history.push({
pathname: '/user/profile',
query: {
name: 'zhangsan',
age: '18'
}
});
}}>跳转到profile</Button>
</div>
);
};
这里我们需要在配置文件中配置如下属性才能够使用query进行传参:
navigate:这里我们可以借助umi中提供的 useNavigate 函数方法来进行编程式路由导航:
import { Button } from "antd";
import { useNavigate } from "umi";
const OrderPage = () => {
// 创建navigate对象
const navigate = useNavigate();
return (
<div>
<h1>我的订单</h1>
<Button type="primary" onClick={()=> {
navigate({
pathname: "/user/profile",
search: "name=zhangsan&age=18",
})
}}>跳转到profile</Button>
</div>
);
};
export default OrderPage;
然后我们在跳转目标页面的组件中使用withRouter来实时获取到当前的传递过来的数据:
import { withRouter } from "umi";
const ProfilePage: React.FC<{ location: any }> = ({ location }) => {
console.log(location.search);
const usp = new URLSearchParams(location.search);
console.log(usp.get("name"));
console.log(usp.get("age"));
return <div>个人信息</div>;
};
export default withRouter(ProfilePage);
最终呈现的效果如下所示:
在UMI的路由跳转中进行传参的方式分为三种,如下:
问号传参:?name=jack&age=18
这里我们就可以使用到编程式路由导航的方法进行问号传参的方式:
路径传参:/profile/jack/18
在路径传参中,我们给路由表配置了如下动态路由形成了路径传参:
设置完成之后,我们正常访问路径的话是访问不到的,需要加上我们设置的动态路由才可以:
那么我们如何获取传递的参数呢?这里我们可以通过umi提供的hook函数来获取当前的路径传参
import { useParams } from "umi";
const CountPage = () => {
const params = useParams();
console.log(params);
return <div>计算中心</div>;
};
export default CountPage;
最终呈现的效果如下所示:
当然我们也可以使用umi中的withRouter来对组件进行包裹,这样打印props的话就会获取到许多我们有用的属性,如:history、location、match、navigate、params等等,代码如下所示:
import { withRouter } from "umi";
const CountPage = (props: any) => {
console.log(props);
return <div>计算中心</div>;
};
export default withRouter(CountPage);
最终在控制台打印的数据,我们可以在match属性中找到我们想要的数据:
隐式传参:state:{name:"ja"}
隐式传参的方式如下所示:
import { Button } from "antd";
import { useNavigate } from "umi";
const OrderPage = () => {
// 创建navigate对象
const navigate = useNavigate();
return (
<div>
<h1>我的订单</h1>
<Button type="primary" onClick={()=> {
// 隐式传参
navigate("/user/profile", {
state: {
name: "zhangsan",
age: 18
},
})
}}>跳转到profile</Button>
</div>
);
};
export default OrderPage;
然后目标组件的话通过 location.state 拿到隐式传参的数据:
当然也是可以采用下面的方式进行隐式传参数据的获取: