当前位置: 首页 > 工具软件 > UMI Admin > 使用案例 >

二、umi路由

慕河
2023-12-01

一、路由

路由有三种方式,分别是,约定式路由(即文件路由,根据文件名自动配置)、编译时配置式路由(config/config.js中配置)和运行时配置式路由(src/app.js中配置)

1、约定式路由

注意:若 .umirc.(ts|js) 或 config/config.(ts|js) 文件中对 router 进行了配置,约定式路由将失效、新添的页面不会自动被 umi 编译,umi 将使用编译时配置式路由

约定式路由也叫文件路由,就是不需要手写配置,文件系统即路由,通过目录和文件及其命名分析出路由配置

  • (1)基础路由: 基础路由,就是自动生成的路由。生成的规则是,pages下面的直接子文件作为pages后面的第一级路由,里面的index.js为斜杠/路径。如下
// 假设 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' },]
  • (2)动态路由: umi 里约定,带 $ 前缀的目录或文件为动态路由。对象路由里面动态路由用表示
// 假设 pages 目录结构如下:
+ pages/
  + $post/
    - index.js
    - comments.js
  + users/
    $id.js
  - index.js
// 那么,umi 会自动生成路由配置如下:
[{ 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' },]
  • (3)可选的动态路由: umi 里约定动态路由如果带 $ 后缀,则为可选动态路由。对象路由里面可选路由用表示
// 假设 pages 目录结构如下:
+ pages/
  + users/
    - $id$.js
  - index.js
// 那么,umi 会自动生成路由配置如下:
[{ path: '/': component: './pages/index.js' },
  { path: '/users/:id?': component: './pages/users/$id$.js' },]
  • (4)嵌套路由: umi 里约定目录下有 _layout.js 时会生成嵌套路由,以 _layout.js 为该目录的 layout。对象路由里面嵌套路由写在routes里面
// 假设 pages 目录结构如下:
+ pages/
  + users/
    - _layout.js
    - $id.js
    - index.js
// 那么,umi 会自动生成路由配置如下:
[{ path: '/users', component: './pages/users/_layout.js',
    routes: [
     { path: '/users/', component: './pages/users/index.js' },
     { path: '/users/:id', component: './pages/users/$id.js' },],},]

2、编译时配置式路由

编译时配置式路由,可以配置 .umirc.(ts|js) 或者config/config.(ts|js) 配置文件中的 routes 属性;如果配置了这个文件,则会使约定式路由无效,即不会对 src/pages 目录做约定式的解析

  • (1)路由配置:config.js文件里面导出的routes属性为一个数组,数组的每一项为一个路由对象,路由对象的参数如下:
    • <1>path参数: 这个就为一个路由路径。默认情况下,访问子路由的时候,会把父路由的所有组件也同时加载出来。 类型:string
      • 如,一个路由{ path: '/', component: '@/layouts/basic',routes:[{path: '/user',component:'./content/content'}] }
      • 这时候如果输入路由 /user, 页面中会同时加载组件basic和组件content
    • <2>component参数: 这个是和前面的路由路径对应的组件路径,即切换到对应的路由,就会显示这个对应的组件。component 默认是相对于 src/pages 目录的。但是也可以用@来进行指定,@目录依然代表src目录。 类型:string
    • <3>routes参数: 表示子路由的所有配置,里面的依然是所有的路由对象
    • <4>redirect参数: 表示重定向路由。值为一个path路径。即,访问该路由的时候,重定向到指定路由
      • { exact: true, path: '/', redirect: '/list' }。即访问路由/的时候,重定向到路由/list
    • <5>exact参数: 表示是否精准匹配。加了这个属性,访问子路由的时候,就不会把父路由的组件也同时加载出来了,而只会加载子路由的组件。 类型:boolean,默认值:false
      • 如,一个路由{ path: '/', component: '@/layouts/basic',routes:[{path: '/user',component:'./content/content',exact: true}] }
      • 这时候如果输入路由 /user, 页面中只会加载content组件
    • <6>title参数:配置路由的标题
  • (2)路由组件参数: 简单说就是,在组件的props上面可以获取到的参数
    • match,当前路由和 url match 后的对象,包含 params(这个params就是动态路由的时候,获取传入的那个值)、path、url 和 isExact 属性
    • location,表示应用当前出于哪个位置,包含 pathname、search、query 等属性。这个参数没用,直接用window.location,就和这个是一样的了
    • history,同 api#history 接口
    • route,当前路由配置,包含 path、exact、component、routes 等
// 下面只是配置的默认导出的一个routers、plugins属性,实际上还可以有其它属性的
export default {
   routes: [
    { path: '/', component: '@/layouts/basic' }, // 这里就是用@来指定目录
    { path: '/list', component: './b',redirect: '/users'},
    { path: '/users', component: './users/_layout',
      routes: [{ path: '/users/detail', component: './users/detail' },
        { path: '/users/:id', component: './users/id' }]},
    ],
    plugins: [['umi-plugin-react',{dva: {immer: true}}],]
};

2.2、权限路由

umi 的权限路由是通过编译时配置式路由的 Routes 属性来实现。对应Authorized.js文件,指定的权限为下面authority里面的那个

{
  path: '/',
  component: '../layouts/BasicLayout',
  Routes: ['src/pages/Authorized'],
  authority: ['admin', 'user'],
}

2.3、路由动效

这里这个动效用的是 react-transition-group,这个用的时候再来看

2.4、启用 Hash 路由

umi 默认是用的 Browser History,如果要用 Hash History,需在config/config.js中配置

export default {history: 'hash',}

3、运行时配置式路由

与运行时配置相关的还有一个叫,编译时配置式路由,就是指config/config.js里面的配置,运行时配置式路由,就是指src 目录下的 app.js 中的路由配置。这个是很重要的

这个就相当于是在配置vue中的全局的钩子函数。即组件里面在执行一些操作的时候,就会先触发这里面的一些函数

下面这些函数,都是写在app.js里面的。并且都需要进行命名空间导出,才有效果

  • (1)patchRoutes()函数: 左右这个函数是用来修改路由当前页面中的路由的,参数如下
    • routes: Arrayconfig/config.js中的全部路由配置,修改了这个routes参数,就相当于修改了全局的路由配置,
    • 使用场景:<1>和 render 配合使用,请求服务端根据响应动态更新路由。<2>修改全部路由,加上某个前缀
// 这个在最前面添加一个 /foo 路由
export function patchRoutes(routes) {
  routes[0].unshift({
    path: '/foo',
    component: require('./routes/foo').default,
  });
}

// 这个就为根据服务端的请求,动态更新路由
let extraRoutes;
export function patchRoutes({ routes }) {
  merge(routes, extraRoutes);
}
export function render() {
  fetch('/api/routes').then((res) => { extraRoutes = res.routes })
}
  • (2)render()函数: 用于这个就是在组件里面的render生命周期执行之前调用,参数如下
    • oldRender: Function,原始组件被捕获之前应该要执行的render 方法,需至少被调用一次
    • 使用场景:渲染应用之前做权限校验,不通过则跳转到登录页
export function render(oldRender) {
    getLoginStatus(); // 这个为登陆验证的方法
    oldRender();
}

// 判断是否进行了登陆
import { history } from 'umi';
export function render(oldRender) {
  fetch('/api/auth').then(auth => {
    if (auth.isLogin) { oldRender() } // 如果登陆了,就执行 组件里面应该执行的render方法
    else { history.push('/login'); } // 没有登陆,就跳转
  });
}
  • (3)onRouteChange()函数: 用于在初始加载和路由切换时触发,参数如下
    • location: Object,history 提供的 location 对象
    • routes: Array,路由配置
    • action: PUSH|POP|REPLACE|undefined,初次加载时为 undefined
    • 使用场景:埋点统计。初次加载时也会执行,但 action 为 undefined
export function onRouteChange({ location, routes, action }) {
  bacon(location.pathname); // 比如bacon为一个进行埋点统计的路由,传入的参数为需要去到的路由页面
}
  • (4)rootContainer: 用于封装 root container,可以取一部分,或者外面套一层,等等,参数如下
    • container: ReactComponent,React 应用最上层的根组件
    • 使用场景:dva、intl 等需要在外层有个 Provider 的场景
export function rootContainer(container) {
  const DvaContainer = require('@tmp/DvaContainer').default;
  return React.createElement(DvaContainer, null, container);
}
  • (5)modifyRouteProps: 用于修改传给路由组件的 props,参数如下
    • props: Object,原始 props
    • Object: 里面有个route属性,表示当前路由配置
    • 使用场景:需返回新的 props
export function modifyRouteProps(props, { route }) {
  return { ...props, foo: 'bar' };
}

二、路由跳转

在 umi 里,页面之间跳转有两种方式:标签跳转和函数跳转

  • 标签跳转: 基于 umi/link,通常作为 React 组件使用。就是说用<link>标签进行跳转
import Link from 'umi/link';
export default () => (<Link to="/list">Go to list page</Link>);
  • 函数跳转: 基于 umi/router,通常在事件处理中被调用。就是说函数式跳转,一般不用这个,在umi 3.0中已经被废弃,而是用下面那个history跳转。更多跳转方法,见 https://umijs.org/zh/api/#umi-router
import router from 'umi/router';
function goToListPage() {router.push('/list');}

原生的react-router实现跳转。使用这个history的时候,有时候会报错 history为undefined,所以这个时候需要withRouter()()这个高阶组件来包裹当前组件

  • props.history.push(params): 这个push()函数的params参数,可以为一个字符串也可以为一个对象。
    • 参数为字符串:为字符串的时候,就代表要跳转的目标路由路径
    • 参数为对象:为对象的时候,就可以 给目标路由传参了
      • pathname属性:表示要跳转的目标路由路径。 类型:string
      • query属性:表示要传给目标路由的参数。不过参数会被放到地址栏。 类型:object
      • state属性:也是传给目标路由的参数。参数是加密的,不会放到地址栏。 类型:object
  • 组件中获取传过来的路由参数:如果是query传过来的对象参数,就用this.props.location.query(默认为{}); 如果是state传过来的对象参数,就用this.props.location.state(默认为undefined);
this.props.history.push('/user/list')

// query传参
this.props.history.push({ pathname : '/sort' ,query : { name: ' sunny'} })
this.props.location.query.name; // 接收参数

// state传参
this.props.history.push({ pathname:'/sort',state:{name : 'sunny' } })
this.props.location.state.name; // 接收参数


// 组件中使用this.props.history
import React, { Component } from 'react';
import { connect } from 'dva';
import {withRouter} from "react-router-dom";
class Test extends Component {
  func(pro) {this.props.history.push({pathname: '/Demo', state: {my: 1111, my2: 2222}})} // 这个时候就可以访问到this.props.history了
  render() {return (<><div onClick={()=>{this.func();}}></div></>);}
}
export default connect(()=>{return {};})(withRouter(Test));

// 另外一个组件中接收传过来的路由参数
class Demo extends Component {
  componentDidMount() {this.props.location.state;} // 输出为{my: 1111, my2: 2222}。如果不是从上面的组件点击跳转的,那么this.props.location.state的值为undefined
}
export default Demo;
  • window的location对象改变路由实现跳转:location.pathname = '/user/list',这种方法可以是可以,不过就是切换路由的速度太慢了。在可以用上面方法的情况下,不推荐使用

三、Module Processor

这个主要就是一些文件在umi中会被自动处理,如下:

.js, .jsx, .mjs, .jsx, .json: 由 babel-loader 处理
.ts: 由 ts-loader 处理
.graphql, .gql: 由 graphql-tag/loader 处理
.css, .less, .sass: 由 css-loader, postcss-loader, less-loader 处理
.svg: 由 @svgr/core 处理。使用 umi,你可以用如下方式引入 svg
import { ReactComponent as Avatar } from './avatar.svg'
function Example() {return <Avatar />}
 类似资料: