吴志勇的博客 吴志勇的博客
  • h5

    • HTML5&CSS3
  • scss

    • css预处理语言
  • JavaScript

    • JavaScript教程
    • Ajax
    • ES6教程
    • NodeJS
    • Typescript
  • 框架

    • Jquery
    • VUE
    • React
  • Swing专题
  • java基础
  • javaweb
  • 框架
  • 数据库
  • netty
  • 设计模式
  • 微服务及架构
  • 云原生
  • maven
  • 单元测试
工具
我的
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

吴志勇

......
  • h5

    • HTML5&CSS3
  • scss

    • css预处理语言
  • JavaScript

    • JavaScript教程
    • Ajax
    • ES6教程
    • NodeJS
    • Typescript
  • 框架

    • Jquery
    • VUE
    • React
  • Swing专题
  • java基础
  • javaweb
  • 框架
  • 数据库
  • netty
  • 设计模式
  • 微服务及架构
  • 云原生
  • maven
  • 单元测试
工具
我的
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • HTML5&CSS3

  • CSS预处理语言

  • JavaScript

  • nodejs

  • webpack

  • VUE

  • react

    • 01 【react入门】
    • 02 【面向组件编程】
    • 03 【事件处理】
    • 04 【生命周期】
    • 05 【条件渲染】
    • 06 【列表 & Key】
    • 07 【收集表单数据】
    • 08 【状态提升】
    • 09 【组合组件】
    • 10 【初始化脚手架】
    • 11 【react-router 5】
    • 12 【react高级指引(上)】
    • 13【react高级指引(下)】
    • 14【react-Hook (上)】
    • 15【react-Hook (下)】
    • 16 【react-router 6】
    • 17【redux】
    • 18 【Redux Toolkit】
    • 19 【RTK Query】
    • 20 【react中使用ts】
    • 21 【styled-components的使用】
    • 22 【在react中使用Emotion】
    • 23 【UmiJS入门】
    • 24 【UmiJS基础】
      • 1.常用配置项
        • 1.1 title
        • 1.2 theme
        • 1.3 favicons
        • 1.4 proxy
        • 1.5 alias
        • 1.6 lessLoader
      • 2.HTML 模板
        • 2.1 修改默认模板
        • 2.2 配置模板
      • 3.样式
        • 3.1 使用 CSS 样式
        • 3.2 使用 CSS Modules
        • 3.3 使用 CSS 预处理器
        • 3.4 使用 Tailwindcss
        • 3.5 使用 UnoCSS
      • 4.使用图片
        • 4.1 JS 里使用图片
        • 4.2 JS 里使用svg
        • 4.3 CSS 里使用图片
        • 4.4 图片路径问题
        • 4.5 Base64 编译
      • 5.编码规范
        • 5.1 使用方式
        • 5.1.1 安装
        • 5.1.2 启用配置
        • 5.1.3 CLI
        • 5.2 与 Git 工作流结合
        • 5.3 Prettier
      • 6.路由
        • 6.1 配置路由
        • 6.1.1 path
        • 6.1.2 component
        • 6.1.3 routes
        • 6.1.4 redirect
        • 6.1.5 wrappers
        • 6.1.6 title
        • 6.2 页面跳转
        • 6.3 错误页配置
        • 6.4 路由组件参数
      • 7.Mock
        • 7.1 目录约定
        • 7.2 Mock 文件
        • 7.2.1 请求方法
        • 7.2.3 自定义函数
        • 7.2.4 defineMock
        • 7.3 关闭 Mock
        • 7.4 引入 Mock.js
  • Typescript
  • 前端
  • react
wuzhiyong
2024-09-22

24 【UmiJS基础】

# 24 【UmiJS基础】

# 1.常用配置项

# 1.1 title

  • 类型:string
  • 默认值:null

配置全局页面 title,暂时只支持静态的 Title。

比如:

export default {
  title: 'hi',
};
1
2
3

此外,你还可以针对路由配置标题,比如,

export default {
  title: 'hi',
  routes: [
    { path: '/', title: 'Home' },
    { path: '/users', title: 'Users' },
    { path: '/foo' },
  ],
};
1
2
3
4
5
6
7
8

然后我们访问 / 标题是 Home,访问 /users 标题是 Users,访问 /foo 标题是默认的 hi。

注意:

  • 默认不会在 HTML 里输出 <title> 标签,通过动态渲染得到
  • 配 exportStatic 后会为每个 HTML 输出 <title> 标签
  • 如果需要自行通过 react-helmet 等方式渲染 title,配 title: false 可禁用内置的 title 渲染机制

# 1.2 theme

  • 类型:object
  • 默认值:{}

配置 less 变量主题。

示例:

export default {
  theme: {
    '@primary-color': '#1DA57A',
  },
};
1
2
3
4
5

# 1.3 favicons

  • 类型:string[]
  • 默认值:null

支持配置多个 favicon 文件。配置 favicons 路径,可以是绝对路径,也可以是基于项目根目录的相对路径。

比如:

export default {
  favicon: [ '/assets/favicon.ico' ],
};
1
2
3

如果要使用本地的图片,图片请放到 public 目录

HTML 中会生成,

<link rel="shortcut icon" type="image/x-icon" href="/assets/favicon.ico" />
1

放到src目录下会自动在html中生成

# 1.4 proxy

  • 类型:object
  • 默认值:{}

配置代理功能。

比如,

proxy: {
  '/api': {
    'target': 'http://jsonplaceholder.typicode.com/',
    'changeOrigin': true,
    'pathRewrite': { '^/api' : '' },
  }
}
1
2
3
4
5
6
7

然后访问 /api/users 就能访问到 http://jsonplaceholder.typicode.com/users 的数据。

注意:proxy 功能仅在 dev 时有效。

# 1.5 alias

  • 类型:Record<string, string>
  • 默认值:{}

配置别名,对 import 语句的 source 做映射。

比如:

{
  alias: {
    foo: '/tmp/to/foo',
  }
}
1
2
3
4
5

然后代码里 import 'foo' 实际上会 import '/tmp/to/foo'。

有几个 Tip。

1、alias 的值最好用绝对路径,尤其是指向依赖时,记得加 require.resolve,比如,

// ⛔
{
  alias: {
    foo: 'foo',
  }
}
 
// ✅
{
  alias: {
    '@c': require('node:path').resolve(__dirname, './src/components'),
  }
}	
1
2
3
4
5
6
7
8
9
10
11
12
13

如果使用了ts,还需要配置

{
	"compilerOptions": {
		"paths": {
			"@c/*": ["src/components/*"],
		}
	}
}
1
2
3
4
5
6
7

这样会把默认的配置覆盖,由于知识限制,暂时还未找到比较好的方法去解决。

2、如果不需要子路径也被映射,记得加 $ 后缀,比如

// import 'foo/bar' 会被映射到 import '/tmp/to/foo/bar'
{
  alias: {
    foo: '/tmp/to/foo',
  }
}
 
// import 'foo/bar' 还是 import 'foo/bar',不会被修改
{
  alias: {
    foo$: '/tmp/to/foo',
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 1.6 lessLoader

  • 类型:Object
  • 默认值:{ modifyVars: userConfig.theme, javascriptEnabled: true }

设置 less-loader 的 Options。具体参考参考 less-loader 的 Options (opens new window)。

默认是用 less@4 版本,如果需要兼容 less@3 请配置使用less-options-math (opens new window)。

src/styles/index.less

@myBg: #bfa;

.myMixin(@mixinBg) {
  background-color: @mixinBg;
}
1
2
3
4
5

.umirc.ts

import { defineConfig } from 'umi'

export default defineConfig({
  lessLoader: {
    modifyVars: {
      hack: `true;@import '@/styles/index.less'`,
    },
  },
})
1
2
3
4
5
6
7
8
9

然后就可以使用全局less定义的变量、混合...

// background-color: @myBg;
.myMixin(#bfa);
1
2

# 2.HTML 模板

# 2.1 修改默认模板

默认模板如下,

<!DOCTYPE html>
<html>
<head><title><%= title %></title></head>
<body>
<div id="<%= mountElementId %>"></div>
</body>
</html>
1
2
3
4
5
6
7

如果自定义模板,请确保包含 <%= title %> 和 <%= mountElementId %>。

新建 src/pages/document.ejs,umi 约定如果这个文件存在,会作为默认模板,比如:

<!doctype html>
<html>
<head>
  <meta charset="utf-8" />
  <title>Your App</title>
</head>
<body>
  <div id="root"></div>
</body>
</html>
1
2
3
4
5
6
7
8
9
10

在 umi 里配置 title 请查看 配置标题 (opens new window)。

# 2.2 配置模板

模板里可通过 context 来获取到 umi 提供的变量,context 包含:

  • route,路由信息,需要打包出多个静态 HTML 时(即配置了 exportStatic 时)有效
  • config,用户配置信息

比如:

<link rel="icon" type="image/x-icon" href="<%= context.config.publicPath %>favicon.png" />
1

# 3.样式

本文介绍各种在 Umi 项目中使用样式的方式。

# 3.1 使用 CSS 样式

你可以在 Umi 项目中使用 .css 文件声明各种样式,然后在 .js 文件中引入即可生效。

例如,在 src/pages/index.css 文件按照以下代码声明 .title 类的样式为红色:

.title {
  color: red;
}
1
2
3

然后在 src/pages/index.js 文件中引入即可生效。

// src/pages/index.js
 
import './index.css';
 
export default function () {
  return <div className="title">Hello World</div>;
}
1
2
3
4
5
6
7

按照此种引入方式的样式会在整个 Umi 项目中生效,即无论你从哪个 .js 文件引入,他声明的样式可以在任何页面和组件中使用。如果你想要避免这种情况,可以使用 CSS Modules (opens new window) 的功能来限制样式的作用域。

# 3.2 使用 CSS Modules

在 js 文件中引入样式时,如果赋予他一个变量名,就可以将样式以 CSS Module 的形式引入。

// src/pages/index.js
 
import styles from './index.css';
 
export default function () {
  return <div className={styles.title}>
    Hello World
  </div>;
}
1
2
3
4
5
6
7
8
9

上面的示例中,index.css 文件中声明的样式不会对全局样式造成影响,只会对从 styles 变量中使用的样式生效。

# 3.3 使用 CSS 预处理器

Umi 默认支持 LESS (推荐), SASS 和 SCSS 样式的导入,你可以直接按照引入 CSS 文件的方式引入并使用这些由 CSS 预处理器处理的样式。

💡

在 Umi 中使用 Sass(Scss) 需要额外安装预处理依赖 如: npm add -D sass

// src/pages/index.js
 
import './index.less';
import './index.sass';
import './index.scss';
 
export default function () {
  return <div className="title">Hello World</div>;
}
1
2
3
4
5
6
7
8
9

同样也支持 CSS Module 的用法:

// src/pages/index.js
 
import lessStyles from './index.less';
import sassStyles from './index.sass';
import scssStyles from './index.scss';
 
export default function () {
  return <div className={lessStyles.title}>
    Hello World
    <p className={sassStyles.blue}>I am blue</p>
    <p className={scssStyles.red}>I am red</p>
  </div>;
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 3.4 使用 Tailwindcss

为项目开启 Tailwind CSS (opens new window) 配置,命令执行后,umi 会生成 Tailwind CSS 和安装相应的的依赖。

$umi g tailwindcss
info  - Write package.json
set config:tailwindcss on /Users/umi/playground/.umirc.ts
set config:plugins on /Users/umi/playground/.umirc.ts
info  - Update .umirc.ts
info  - Write tailwind.config.js
info  - Write tailwind.css
1
2
3
4
5
6
7

生成的tailwind.css文件会有警告,可以通过vscode的配置来解决

settings.json

{
  "css.lint.unknownAtRules": "ignore"
}
1
2
3

# 3.5 使用 UnoCSS

与 Tailwindcss 相同,Umi 也提供了内置的 UnoCSS (opens new window) 插件,可以按照相同方式开启。

  1. 安装 plugin-unocss
  2. 安装 unocss 及 @unocss/cli
pnpm i unocss @unocss/cli
1
  1. 在 Umi 设置中启用插件,并声明会用到 unocss 的文件目录
// .umirc.ts
 
export default {
  plugins: [
    require.resolve('@umijs/plugins/dist/unocss')
  ],
  unocss: {
    // 检测 className 的文件范围,若项目不包含 src 目录,可使用 `pages/**/*.tsx`
    watch: ['src/**/*.tsx']
  },
};
1
2
3
4
5
6
7
8
9
10
11
  1. 在项目目录下加入 unocss.config.ts 配置文件,并加入项目需要的 UnoCSS Presets (opens new window)
// unocss.config.ts
 
import {defineConfig, presetAttributify, presetUno} from 'unocss';
 
export function createConfig({strict = true, dev = true} = {}) {
  return defineConfig({
    envMode: dev ? 'dev' : 'build', presets: [presetAttributify({strict}), presetUno()],
  });
}
 
export default createConfig(); 
1
2
3
4
5
6
7
8
9
10
11
  1. 启动项目进行开发,插件会监听设置文件中的 unocss.watch 字段,动态生成样式文件并自动套用

# 4.使用图片

# 4.1 JS 里使用图片

通过 require 引用相对路径的图片。

比如:

export default () => <img src={require('./foo.png')} />
1

支持别名,比如通过 @ 指向 src 目录:

export default () => <img src={require('@/foo.png')} />
1

# 4.2 JS 里使用svg

组件式引入

import { ReactComponent as Logo } from './logo.svg'
function Analysis() {  return <Logo width={90} height={120} />}
1
2

url式引入

import logoSrc from './logo.svg'
function Analysis() {  return <img src={logoSrc} alt="logo" />}
1
2

# 4.3 CSS 里使用图片

通过相对路径引用。

比如,

.logo {
  background: url(./foo.png);
}
1
2
3

CSS 里也支持别名,但需要在前面加 ~ 前缀,

.logo {
  background: url(~@/foo.png);
}
1
2
3

注意:

  1. 这是 webpack 的规则,如果切到其他打包工具,可能会有变化
  2. less 中同样适用

# 4.4 图片路径问题

项目中使用图片有两种方式,

  1. 先把图片传到 cdn,然后在 JS 和 CSS 中使用图片的绝对路径
  2. 把图片放在项目里,然后在 JS 和 CSS 中通过相对路径的方式使用

# 4.5 Base64 编译

通过相对路径引入图片的时候,如果图片小于 10K,会被编译为 Base64,否则会被构建为独立的图片文件。

10K 这个阈值可以通过 inlineLimit 配置 (opens new window)修改。

# 5.编码规范

我们通常会在项目中使用 ESLint、Stylelint 来协助我们把控编码质量,为了实现低成本、高性能、更稳定地接入上述工具,Umi 提供了开箱即用的 Lint 能力,包含以下特性:

  1. 推荐配置:提供 ESLint 及 Stylelint 推荐配置,可以直接继承使用
  2. 统一的 CLI:提供 umi lint CLI,集成式调用 ESLint 和 Stylelint
  3. 规则稳定:始终确保规则的稳定性,不会出现上游配置更新导致存量项目 lint 失败的情况

其中,ESLint 配置具备如下特点:

  1. 仅质量相关:我们从数百条规则中筛选出数十条与编码质量相关的规则进行白名单开启,回归 Lint 本质,且不会与 Prettier 的规则冲突
  2. 性能优先:部分 TypeScript 的规则实用型低但项目全量编译的成本却很高,我们对这些规则进行禁用以提升性能
  3. 内置常用插件:包含 react、react-hooks、@typescript/eslint、jest,满足日常所需

另外,Stylelint 配置还内置 CSS-in-JS 支持,可以检测出 JS 文件中的样式表语法错误。听起来很有吸引力?来看看如何接入吧。

# 5.1 使用方式

# 5.1.1 安装

为了节省安装体积,目前仅在 Umi Max 中内置了 Lint 模块,使用 max lint 来执行 lint 过程。如果你使用的是 Umi,需要先安装 @umijs/lint:

$ npm i @umijs/lint -D
# or
$ pnpm add @umijs/lint -D
1
2
3

然后安装 ESLint 及 Stylelint:

$ npm i eslint stylelint -D
# or
$ pnpm add eslint stylelint -D
1
2
3

# 5.1.2 启用配置

在 .eslintrc.js 及 .stylelintrc.js 里继承 Umi 提供的配置:

// .eslintrc.js
module.exports = {
  // Umi 项目
  extends: require.resolve('umi/eslint'),
 
  // Umi Max 项目
  extends: require.resolve('@umijs/max/eslint'),
  
   settings: {
    // 解决警告:Warning: React version was set to "detect" in eslint-plugin-react settings, but the "react" package is not installed. Assuming latest React version for linting.
    react: {
      version: '999.999.999',
    },
  },
}
 
// .stylelintrc.js
module.exports = {
  // Umi 项目
  // pnpm add stylelint-config-recess-order -D 
  extends: [require.resolve('umi/stylelint'), 'stylelint-config-recess-order'],
 
  // Umi Max 项目
  extends: [require.resolve('@umijs/max/stylelint'), 'stylelint-config-recess-order'],
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

编写检查忽略文件 .eslintignore 及 .stylelintignore 里继承 Umi 提供的配置:

# .eslintrc.js
/config
/dist
public
dist
.umi
mock
node_modules
 
# .stylelintrc.js
node_modules
.umi
.umi-production
tailwind.*
1
2
3
4
5
6
7
8
9
10
11
12
13
14

在配置文件创建完毕后,我们其实已经可以通过 eslint、stylelint 命令来执行 lint 了,但我们仍然推荐使用 umi lint 命令,以获得更便捷的体验。

# 5.1.3 CLI

umi lint 命令的用法如下:

$ umi lint [glob] [--fix] [--eslint-only] [--stylelint-only] [--cssinjs]
1

参数说明:

 [glob]: 可选,指定要 lint 的文件,默认为 `{src,test}/**/*.{js,jsx,ts,tsx,css,less}`
  --quiet: 可选,禁用 `warn` 规则的报告,仅输出 `error`
  --fix: 可选,自动修复 lint 错误
  --eslint-only: 可选,仅执行 ESLint
  --stylelint-only: 可选,仅执行 Stylelint
  --cssinjs: 可选,为 Stylelint 启用 CSS-in-JS 支持
1
2
3
4
5
6

通常来说,直接执行 umi lint 应该就能满足大部分情况。

# 5.2 与 Git 工作流结合

# 5.3 Prettier

在启用 umi lint 的基础上,我们也建议与 Prettier (opens new window) 一同使用,以确保团队的代码风格是基本一致的。

为项目生成 prettier (opens new window) 配置,命令执行后,umi 会生成推荐的 prettier 配置和安装相应的依赖。

$umi g prettier
info  - Write package.json
info  - Write .prettierrc
info  - Write .prettierignore
1
2
3
4

我的.prettierrc配置

{
  "printWidth": 120,
  "tabWidth": 2,
  "semi": false,
  "singleQuote": true,
  "trailingComma": "all",
  "proseWrap": "never",
  "arrowParens": "avoid",
  "htmlWhitespaceSensitivity": "strict",
  "endOfLine": "auto",
  "bracketSpacing": true,
  "jsxSingleQuote": false,
  "bracketSameLine": false,
  "useTabs": false,
  "overrides": [{ "files": ".prettierrc", "options": { "parser": "json" } }],
  "plugins": ["prettier-plugin-organize-imports", "prettier-plugin-packagejson"]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

可参考 Prettier 文档将其配置到 lint-staged 中:https://prettier.io/docs/en/install.html#git-hooks

# 6.路由

在 Umi 应用是单页应用 (opens new window),页面地址的跳转都是在浏览器端完成的,不会重新请求服务端获取 html,html 只在应用初始化时加载一次。所有页面由不同的组件构成,页面的切换其实就是不同组件的切换,你只需要在配置中把不同的路由路径和对应的组件关联上。

# 6.1 配置路由

在配置文件中通过 routes 进行配置,格式为路由信息的数组。

比如:

export default {
  routes: [
    { path: '/', component: 'index' },
    { path: '/user', component: 'user' },
  ],
}
1
2
3
4
5
6

Umi 4 默认根据路由来进行 JavaScript 模块按需加载。如果需要在路由组件加载的过程中配置自定义加载组件,在项目 src 目录下创建 loading.tsx 或者 loading.jsx 或者 loading.js 文件,默认导出的组件会在组件加载的时候渲染。

💡

你可以在 Chrome 的调试工具的网络 tab 中将网络设置成低速,然后切换路由查看动态加载中组件的展示。

# 6.1.1 path

  • Type: string

path 只支持两种占位符配置,第一种是动态参数 :id 的形式,第二种是 * 通配符,通配符只能出现路由字符串的最后。

✅ 以下是目前***支持***的路由路径配置形式:

/groups
/groups/admin
/users/:id
/users/:id/messages
/files/*
/files/:id/*
1
2
3
4
5
6

❌ 以下是目前***不支持***的路由路径配置形式:

/users/:id?
/tweets/:id(\d+)
/files/*/cat.jpg
/files-*
1
2
3
4

# 6.1.2 component

  • Type: string

配置 location 和 path 匹配后用于渲染的 React 组件路径。可以是绝对路径,也可以是相对路径,如果是相对路径,会从 src/pages 开始找起。

如果指向 src 目录的文件,可以用 @,也可以用 ../。比如 component: '@/layouts/basic',或者 component: '../layouts/basic',推荐用前者。

# 6.1.3 routes

配置子路由,通常在需要为多个路径增加 layout 组件时使用。

比如:

export default {
  routes: [
    { path: '/login', component: 'login' },
    {
      path: '/',
      component: '@/layouts/index',
      routes: [
        { path: '/list', component: 'list' },
        { path: '/admin', component: 'admin' },
      ],
    }, 
  ],
}
1
2
3
4
5
6
7
8
9
10
11
12
13

然后在 src/layouts/index 中通过 <Outlet/> 渲染子路由,

import {Outlet} from 'umi'
 
export default (props) => {
  return <div style={{ padding: 20 }}> 
    <Outlet/> 
  </div>;
}
1
2
3
4
5
6
7

这样,访问 /list 和 /admin 就会带上 src/layouts/index 这个 layout 组件。

# 6.1.4 redirect

  • Type: string

配置路由跳转。

比如:

export default {
  routes: [
    { path: '/', redirect: '/list' },
    { path: '/list', component: 'list' },
  ],
}
1
2
3
4
5
6

访问 / 会跳转到 /list,并由 src/pages/list 文件进行渲染。

# 6.1.5 wrappers

  • Type: string[]

配置路由组件的包装组件,通过包装组件可以为当前的路由组件组合进更多的功能。 比如,可以用于路由级别的权限校验:

export default {
  routes: [
    { path: '/user', component: 'user',
      wrappers: [
        '@/wrappers/auth',
      ],
    },
    { path: '/login', component: 'login' },
  ]
}
1
2
3
4
5
6
7
8
9
10

然后在 src/wrappers/auth 中,

import { Navigate, Outlet } from 'umi'
 
export default (props) => {
  const { isLogin } = useAuth();
  if (isLogin) {
    return <Outlet />;
  } else{
    return <Navigate to="/login" />;
  }
}
1
2
3
4
5
6
7
8
9
10

这样,访问 /user,就通过 auth 组件做权限校验,如果通过,渲染 src/pages/user,否则跳转到 /login。

🚨

wrappers 中的每个组件会给当前的路由组件增加一层嵌套路由,如果你希望路由结构不发生变化,推荐使用高阶组件。先在高阶组件中实现 wrapper 中的逻辑,然后使用该高阶组件装饰对应的路由组件。

举例:

// src/hocs/withAuth.jsx
import { Navigate } from 'umi'
 
const withAuth = (Component) => ()=>{
  const { isLogin } = useAuth();
  if (isLogin) {
    return <Component />;
  } else{
    return <Navigate to="/login" />;
  }
}
1
2
3
4
5
6
7
8
9
10
11
// src/pages/user.jsx
 
const TheOldPage = ()=>{
  ...
}
 
export default withAuth(TheOldPage)
1
2
3
4
5
6
7

# 6.1.6 title

  • Type: string

配置路由的标题。

# 6.2 页面跳转

命令式跳转请使用 history (opens new window) API

和 history 相关的操作,用于获取当前路由信息、执行路由跳转、监听路由变更。

// 建议组件或 hooks 里用 useLocation 取
import { useLocation } from 'umi';
export default function Page() {
  let location = useLocation();
  return (
    <div>
     { location.pathname }
     { location.search }
     { location.hash }
    </div>
  );
}
1
2
3
4
5
6
7
8
9
10
11
12

如果在 React 组件和 Hooks 之外获取当前路由信息。

// location 对象,包含 pathname、search 和 hash
window.location.pathname;
window.location.search;
window.location.hash;
1
2
3
4

命令式路由跳转。

import { history } from 'umi';
 
// 跳转到指定路由
history.push('/list');
 
// 带参数跳转到指定路由
history.push('/list?a=b&c=d#anchor', state);
history.push({
    pathname: '/list',
    search: '?a=b&c=d',
    hash: 'anchor',
  },
  {
    some: 'state-data',
  }
);
 
// 跳转当前路径,并刷新 state
history.push({}, state)
 
// 跳转到上一个路由
history.back();
history.go(-1);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

🚨

注意:history.push 和 history.replace 需要使用 state 需将 state 作为这两个 API 的第二个参数传递

路由监听。

import { history } from 'umi';
 
const unlisten = history.listen(({ location, action }) => {
  console.log(location.pathname);
});
unlisten();
1
2
3
4
5
6

组件内还可以使用 useNavigate (opens new window) hook

useNavigate 钩子函数返回一个可以控制跳转的函数;比如可以用在提交完表单后跳转到其他页面。

declare function useNavigate(): NavigateFunction;
 
interface NavigateFunction {
  (
    to: To,
    options?: { replace?: boolean; state?: any }
  ): void;
  (delta: number): void;
}
1
2
3
4
5
6
7
8
9

# 6.3 错误页配置

src/404.tsx

export default function Error() {
  return <div>404</div>
}
1
2
3

.umirc.ts

routes: [
	...
  {
    path: '*',
    component: '@/404.tsx',
    title: '错误-404',
  },
],
1
2
3
4
5
6
7
8

示例:

  • 跳转路径
import { useNavigate } from 'umi';
 
let navigate = useNavigate();
navigate("../success", { replace: true });
1
2
3
4
  • 返回上一页
import { useNavigate } from 'umi';
 
let navigate = useNavigate();
navigate(-1);
1
2
3
4

# 6.4 路由组件参数

Umi4 使用 react-router@6 (opens new window) 作为路由组件,路由参数的获取使其 hooks。

# 7.Mock

Umi 提供了开箱即用的 Mock 功能,能够用方便简单的方式来完成 Mock 数据的设置。

💡

什么是 Mock 数据:在前后端约定好 API 接口以后,前端可以使用 Mock 数据来在本地模拟出 API 应该要返回的数据,这样一来前后端开发就可以同时进行,不会因为后端 API 还在开发而导致前端的工作被阻塞。

# 7.1 目录约定

Umi 约定 /mock 目录下的所有文件为 Mock 文件 (opens new window),例如这样的目录结构:

.
├── mock
    ├── todos.ts
    ├── items.ts
    └── users.ts
└── src
    └── pages
        └── index.tsx
1
2
3
4
5
6
7
8

则 /mock 目录中的 todos.ts, items.ts 和 users.ts 就会被 Umi 视为 Mock 文件 (opens new window) 来处理。

# 7.2 Mock 文件

Mock 文件默认导出一个对象,而对象的每个 Key 对应了一个 Mock 接口,值则是这个接口所对应的返回数据,例如这样的 Mock 文件:

// ./mock/users.ts
 
export default {
 
  // 返回值可以是数组形式
  'GET /api/users': [
    { id: 1, name: 'foo' },
    { id: 2, name: 'bar' }
  ],
 
  // 返回值也可以是对象形式
  'GET /api/users/1': { id: 1, name: 'foo' },
 
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

就声明了两个 Mock 接口,透过 GET /api/users 可以拿到一个带有两个用户数据的数组,透过 GET /api/users/1 可以拿到某个用户的模拟数据。

# 7.2.1 请求方法

当 Http 的请求方法是 GET 时,可以省略方法部分,只需要路径即可,例如:

// ./mock/users.ts
 
export default {
 
  '/api/users': [
    { id: 1, name: 'foo' },
    { id: 2, name: 'bar' }
  ],
 
  '/api/users/1': { id: 1, name: 'foo' },
 
}
1
2
3
4
5
6
7
8
9
10
11
12

也可以用不同的请求方法,例如 POST,PUT,DELETE:

// ./mock/users.ts
 
export default {
 
  'POST /api/users': { result: 'true' },
 
  'PUT /api/users/1': { id: 1, name: 'new-foo' },
 
}
1
2
3
4
5
6
7
8
9

# 7.2.3 自定义函数

除了直接静态声明返回值,也可以用函数的方式来声明如何计算返回值,例如:

export default {
 
  'POST /api/users/create': (req, res) => {
    // 添加跨域请求头
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.end('ok');
  }
 
}
1
2
3
4
5
6
7
8
9

关于 req 和 res 的 API 可参考 Express@4 官方文档 (opens new window) 来进一步了解。

# 7.2.4 defineMock

另外,也可以使用 defineMock 类型帮助函数来提供编写 mock 对象的代码提示,如:

import { defineMock } from "umi";
 
export default defineMock({
  "/api/users": [
    { id: 1, name: "foo" },
    { id: 2, name: "bar" },
  ],
  "/api/users/1": { id: 1, name: "foo" },
  "GET /api/users/2": (req, res) => {
    res.status(200).json({ id: 2, name: "bar" });
  },
});
1
2
3
4
5
6
7
8
9
10
11
12

defineMock 仅仅提供类型提示,入参与出参完全一致。

# 7.3 关闭 Mock

Umi 默认开启 Mock 功能,如果不需要的话可以从配置文件关闭:

// .umirc.ts
 
export default {
  mock: false,
};
1
2
3
4
5

或是用环境变量的方式关闭:

MOCK=none umi dev
1

# 7.4 引入 Mock.js

在 Mock 中我们经常使用 Mock.js (opens new window) 来帮我们方便的生成随机的模拟数据,如果你使用了 Umi 的 Mock 功能,建议你搭配这个库来提升模拟数据的真实性:

import mockjs from 'mockjs';
 
export default {
  // 使用 mockjs 等三方库
  'GET /api/tags': mockjs.mock({
    'list|100': [{ name: '@city', 'value|1-100': 50, 'type|0-2': 1 }],
  }),
};
1
2
3
4
5
6
7
8
上次更新: 2024-09-30 01:09:25

← 23 【UmiJS入门】 Typescript→

Copyright © 2020-2025 wuzhiyong
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式