小白视角学antd umi(二) - 约定式路由

这篇文章主要介绍一下umi约定式路由的使用。主要参考umi官方文档:https://umijs.org/zh-CN/docs/convention-routing

一、 基本使用

约定式路由是以文件系统为基础的路由。umi会分析src/pages目录,并根据目录文件结构自动生成对应的路由。如果你用过Jekyll或者Hugo之类的网页生成器,那就很容易理解约定式路由。

下面我们就来尝试一下。首先先看一下现在src/pages的目录结构(上一篇文章的脚手架创建的项目):

src
└── pages
    ├── index.less
    └── index.tsx

我们来添加一个新的页面page1:

src
└── pages
    ├── index.less
    └── index.tsx
    └── page1.js

为了简便起见,这里使用了javascript,当然你也可以使用typescript。页面代码:

//page1.js
import React from 'react'

export default function Page1(props){
  return(
    <div>
      This is page 1.
    </div>
  )
}

运行项目:

yarn start

打开浏览器 http://localhost:8000/page1 预览一下:

empty page

怎么是空白页面?因为umi约定只有当配置文件中没有routes这一项时才会启用约定式路由,所以我们还需要注释掉配置文件中的route配置:

//.umirc.ts
import { defineConfig } from 'umi';

export default defineConfig({
  nodeModulesTransform: {
    type: 'none',
  },
  // routes: [
  //   { path: '/', component: '@/pages/index' },
  // ],
});

此时再预览一下,页面可以正常显示了。
page 1

当然,开发时为了更好的组织文件,我们会把有些非页面的文件或文件夹一起放到pages路径里。Umi提供了几种排除规则,满足以下规则的文件不会被注册为约定式路由:

  • ._ 开头的文件或目录
  • d.ts 结尾的类型定义文件
  • test.tsspec.tse2e.ts 结尾的测试文件(适用于 .js.jsx.tsx 文件)
  • componentscomponent 目录
  • utilsutil 目录
  • 不是 .js.jsx.ts.tsx 文件
  • 文件内容不包含 JSX 元素

二、 动态路由

Umi约定以[]包裹的文件或文件夹为动态路由。我们直接来试一下,将刚刚创建的page1.js改成[page].js:

src
└── pages
    ├── index.less
    └── index.tsx
    └── [page].js
//[page].js
import React from 'react'

export default function Page(props){

  return(
    <div>
      This is page {props.match.params.page}.
    </div>
  )
}

在组件中,我们可以通过props.match.params获取到动态url中的变量对象,然后通过相应的变量名获取变量值,这里的变量名就是page

回到浏览器预览一下:http://localhost:8000/1024。可以任意修改url,页面会显示对应的参数。

dynamic

注意:如果你发现路由失效了,或者没有更新,可以删除整个 src/.umi 目录,然后重新运行 yarn start。关于原因和.umi目录的作用,有时间会在之后的文章中探索一下。

三、 嵌套路由

Umi 里约定目录下有 _layout.tsx 时会生成嵌套路由。让我们再来更改一下页面:

src
└── pages
    ├── index.less
    └── index.tsx
    └── page1
        └──_layout.js
        └──child1.js
//_layout.js
import React from 'react'

export default (props)=>{

  return(
    <>
      <h1>This is page layout.</h1>
      { props.children }
    </>
  )
}

//child1.js
import React from 'react';

export default (props)=>{
  return(
    <h2>This is child 1.</h2>
  )
}

这样我们就可以通过localhost/page1localhost/page1/child1来分别访问了。

nest page 1
nest page1 child1

注意page1路径下的所有文件都会携带_layout的布局。一般可以把页头,页脚,菜单等组件抽象出来放在_layout中。如果不想要共有的组件,那只需要把_layout里的多余元素清空即可:

//_layout.js
import React from 'react'

export default (props)=>{

  return(
    <>
      { props.children }
    </>
  )
}

四、 查看路由表

约定式路由不需要开发者手动编写路由配置,umi会自动分析目录并生成路由表。我们可以观察一下生成的路由文件:src\.umi\core\routes.ts

// @ts-nocheck
import React from 'react';
import { ApplyPluginsType } from 'C:***/node_modules/@umijs/runtime';
import * as umiExports from './umiExports';
import { plugin } from './plugin';

export function getRoutes() {
  const routes = [
  {
    "path": "/",
    "exact": true,
    "component": require('@/pages/index.tsx').default
  },
  {
    "path": "/page1",
    "routes": [
      {
        "path": "/page1/child1",
        "exact": true,
        "component": require('@/pages/page1/child1.js').default
      }
    ],
    "component": require('@/pages/page1/_layout.js').default
  }
];

  // allow user to extend routes
  plugin.applyPlugins({
    key: 'patchRoutes',
    type: ApplyPluginsType.event,
    args: { routes },
  });

  return routes;
}

可以看到我们刚刚编写的嵌套路由其实就是在/page1下在嵌套一个routes属性。

五、 添加404页面

根据官方文档的说明,只需要在src\pages路径下添加404.tsx文件即可。我们来试一下:

src
└── pages
    ├── index.less
    └── index.tsx
    └── page1
        └──_layout.js
        └──child1.js
    └── 404.tsx
//404.tsx
import React from 'react';

export default ()=>{
  return(
    <h1>404</h1>
  )
}

然后随便输入一个url,比如http://localhost:8000/page1024。你会发现页面是空白。再试一下这个url,http://localhost:8000/404,可以显示404。

官方文档说404文件会被解析为:

 { component: '@/pages/404' }

并添加到路由表的末尾,我们可以查看一下routes.ts文件:

  ...

  const routes = [
  {
    "path": "/404",
    "exact": true,
    "component": require('@/pages/404.tsx').default
  },
  {
    "path": "/",
    "exact": true,
    "component": require('@/pages/index.tsx').default
  },
  {
    "path": "/page1",
    "routes": [
      {
        "path": "/page1/child1",
        "exact": true,
        "component": require('@/pages/page1/child1.js').default
      }
    ],
    "component": require('@/pages/page1/_layout.js').default
  }
];

...

发现404并没有正确解析。那么我们手动修改一下route.ts文件呢?

  ...

  const routes = [
  {
    "path": "/",
    "exact": true,
    "component": require('@/pages/index.tsx').default
  },
  {
    "path": "/page1",
    "routes": [
      {
        "path": "/page1/child1",
        "exact": true,
        "component": require('@/pages/page1/child1.js').default
      }
    ],
    "component": require('@/pages/page1/_layout.js').default
  },
  {
    "component": require('@/pages/404.tsx').default
  },
];

...

在打开http://localhost:8000/page1024。发现,这回成功了。

404 working

但是要注意的是,route.ts文件在开发中是会不断被重新构建的,所以不可以用这种方法解决问题。目前看来可能是一个小bug,我们需要持续关注umi的github issue看看官方后续有没有说明。

总结一下

Umi的约定式路由总的来说还是很方便的,但是3.x新版本貌似还不太为稳定,会有一些小的问题,比如添加404页面的问题。期望官方后期推出更新解决这些问题。接下来的文章将要介绍配置式路由的使用。


版权声明:本文为mayazure原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。