Umijs笔记

一、快速上手

文档:https://v3.umijs.org/zh-CN

1. 环境准备

推荐使用 yarn 管理 npm 依赖

npm i yarn tyarn -g

2. 脚手架使用

2.1 新建目录

mkdir [项目名称] && cd [项目名称]

2.2 创建项目

yarn create @umijs/umi-app

2.3 安装依赖

yarn

2.4 启动项目

yarn start

二、目录结构

├── package.json
├── .umirc.ts # 配置文件,包含 umi 内置功能和插件的配置。
├── .env
├── dist
├── mock # 存储 mock 文件,此目录下所有 js 和 ts 文件会被解析为 mock 文件。
├── public # 此目录下所有文件会被 copy 到输出路径。(不会被打包)
└── src
    ├── .umi
    ├── layouts/index.tsx # 约定式路由时的全局布局文件。
    ├── pages # 所有路由组件存放在这里。
        ├── index.less
        └── index.tsx
    └── app.ts # 运行时配置文件,可以在这里扩展运行时的能力,比如动态修改路由、修改 render 方法等。

三、常用配置

1. 配置

Umi 在 .umirc.ts 或 config/config.ts 中配置项目和插件,支持 es6。一份常见的配置如下

如果项目的配置不复杂,推荐在 .umirc.ts 中写配置; 如果项目的配置比较复杂,可以将配置写在 config/config.ts 中,并把配置的一部分拆分出去,比如路由配置可以拆分成单独的 routes.ts

2. hash

配置是否让生成的文件包含 hash 后缀,通常用于增量发布和避免浏览器加载缓存。一般是在执行build命令时,打包的文件会带上文件指纹。

3. bash

设置路由前缀,通常用于部署到非根目录。

比如,你有路由 / 和 /users,然后设置了 base 为 /foo/,那么就可以通过 /foo/ 和 /foo/users 访问到之前的路由。

4. publicPath

配置 webpack 的 publicPath。当打包的时候,webpack 会在静态文件路径前面添加 publicPath 的值,当你需要修改静态文件地址时,比如使用 CDN 部署,把 publicPath 的值设为 CDN 的值就可以。如果使用一些特殊的文件系统,比如混合开发或者 cordova 等技术,可以尝试将 publicPath 设置成 ./ 相对路径。

5. outputPath

指定输出路径。

注意:不允许设定为 src、public、pages、mock、config 等约定目录

6. title

配置标题。

比如:

export default {
  title: 'hello umijs',
};

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

export default {
  title: 'hello umijs',
  routes: [
    { path: '/', title: 'Home' },
    { path: '/users', title: 'Users' },
    { path: '/foo' },
  ],
};

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

路由的title会高于去全局的title

7. history

路由模式

  • Type: object
  • Default: { type: 'browser' }

8. targets

配置需要兼容的浏览器最低版本,会自动引入 polyfill 和做语法转换。

比如要兼容 ie11,需配置

export default {
  targets: {
    ie: 11,
  },
};

9. proxy

配置代理能力。

export default {
  proxy: {
    '/api': {
      'target': 'http://jsonplaceholder.typicode.com/',
      'changeOrigin': true,
      'pathRewrite': { '^/api' : '' },
    },
  },
}

注意:proxy 配置仅在 dev 时生效。

10. theme

配置主题,实际上是配 less 变量。

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

11. routes

配置路由,umi 的路由基于 react-router@5 实现,配置和 react-router 基本一致

四、路由

1. 配置路由

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

.umirc.ts文件中:

export default {
  routes: [
    { path: '/', component: '@/pages/index' },
    { path: '/user', component: '@/pages/user' },
  ],
}

2. component

配置 locationpath 匹配后用于渲染的 React 组件路径。可以是绝对路径,也可以是相对路径,如果是相对路径,会从 src/pages 开始找起。如果指向 src 目录的文件,可以用 @,也可以用 ../

3. exact

表示是否严格匹配,即 location 是否和 path 完全对应上。

4. routes

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

export default {
  routes: [
    { path: '/login', component: 'login' },
    {
      path: '/',
      component: '@/layouts/index',
      routes: [
        { path: '/list', component: 'list' },
        { path: '/admin', component: 'admin' },
      ],
    }, 
  ],
}

然后在 src/layouts/index 中通过 props.children 渲染子路由,

export default (props) => {
  return <div>{ props.children }</div>;
}

5. redirect

配置路由跳转。

export default {
  routes: [
    { exact: true, path: '/', redirect: '/list' },
    { exact: true, path: '/list', component: 'list' },
  ],
}

6. wrappers

  • Type: string[]

配置路由的高阶组件封装。比如,可以用于路由级别的权限校验:

export default {
  routes: [
    { path: '/user', component: 'user',
      wrappers: [
        '@/wrappers/auth',
      ],
    },
    { path: '/login', component: 'login' },
  ]
}

然后在 src/wrappers/auth 中,

import { Redirect } from 'umi'

export default (props) => {
  const { isLogin } = useAuth();
  if (isLogin) {
    return <div>{ props.children }</div>;
  } else {
    return <Redirect to="/login" />;
  }
}

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

7. title

配置路由的标题。

8. 页面跳转

import { history } from 'umi';

// 跳转到指定路由
history.push('/list');

// 带参数跳转到指定路由
history.push('/list?a=b');
history.push({
  pathname: '/list',
  query: {
    a: 'b',
  },
});

// 跳转到上一个路由
history.goBack();

9. 动态路由

export default {
  routes: [
    { path: '/user/:id', component: 'user' }, // 动态路由,id必传
    { path: '/user2/:id?', component: 'user' }, // 动态路由,id可不传
  ],
}

可以通过组件的props获取到路由参数

10. 路由组件参数

路由组件可通过 props 获取到以下属性:

  • match,当前路由和 url match 后的对象,包含 paramspathurlisExact 属性
  • location,表示应用当前处于哪个位置,包含 pathnamesearchquery 等属性
  • history,同 api#history 接口
  • route,当前路由配置,包含 pathexactcomponentroutes
  • routes,全部路由信息

五、约定式路由

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

如果没有 routes 配置,Umi 会进入约定式路由模式,然后分析 src/pages 目录拿到路由配置。

比如以下文件结构:

.
  └── pages
    ├── index.tsx
    └── users.tsx

会得到以下路由配置,

[
  { exact: true, path: '/', component: '@/pages/index' },
  { exact: true, path: '/users', component: '@/pages/users' },
]

需要注意的是,满足以下任意规则的文件不会被注册为路由:

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

六、页面跳转

1. 声明式

通过 Link 使用,通常作为 React 组件使用

import { Link } from 'umi';

export default () => (
  <Link to="/list">Go to list page</Link>
);

2. 命令式

  1. 通过 history 使用,通常在事件处理中被调用。
import { history } from 'umi';

function goToListPage() {
  history.push('/list');
}
  1. 也可以直接从组件的属性props中取得 history
export default (props) => (
  <Button onClick={()=>props.history.push('/list');}>Go to list page</Button>
);

3. history

3.1 history用于获取当前路由信息

import { history } from 'umi';

// history 栈里的实体个数
console.log(history.length);

// 当前 history 跳转的 action,有 PUSH、REPLACE 和 POP 三种类型
console.log(history.action);

// location 对象,包含 pathname、search 和 hash
console.log(history.location.pathname);
console.log(history.location.search);
console.log(history.location.hash);

3.2 history用于路由跳转

import { history } from 'umi';

// 跳转到指定路由
history.push('/list');

// 带参数跳转到指定路由
history.push('/list?a=b');
history.push({
  pathname: '/list',
  query: {
    a: 'b',
  },
});

// 跳转到上一个路由
history.goBack();

3.3 history用于路由监听

import { history } from 'umi';

const unlisten = history.listen((location, action) => {
  console.log(location.pathname);
});
unlisten();

七、HTML模板

在原始的react脚手架或vite创建的项目,会存在一个index.html模板,有个id为root的节点用来挂载组件,但在umijs创建的项目的目录结构中没有index.html模板,该模板放在了umi这个包中。

1. 修改默认模板

新建 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>

2. 配置模板

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

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

例如:

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

八、Mock数据

1. 约定式 Mock 文件

Umi 约定 /mock 文件夹下所有文件为 mock 文件。

比如:

.
├── mock
    ├── api.ts
    └── users.ts
└── src
    └── pages
        └── index.tsx

/mock 下的 api.tsusers.ts 会被解析为 mock 文件。

2. 编写 Mock 文件

export default {
  // 支持值为 Object 和 Array
  'GET /api/users': { users: [1, 2] },

  // GET 可忽略
  '/api/users/1': { id: 1 },

  // 支持自定义函数,API 参考 express@4
  'POST /api/users/create': (req, res) => {
    // 添加跨域请求头
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.end('ok');
  },
}

3. 引入 Mock.js

import mockjs from 'mockjs';

export default {
  // 使用 mockjs 等三方库
  'GET /api/tags': mockjs.mock({
    'list|100': [{ name: '@city', 'value|1-100': 50, 'type|0-2': 1 }],
  }),
};

4. 使用

umijs中内置了plugin-request(基于 umi-request 和 umi-hooks 的请求方案)

import { Button } from 'antd';
import { request } from 'umi';

export default function IndexPage() {
  const getData = async () => {
    let res = await request('/list')
    console.log(res);
  };

  return (
    <div>
      <Button type="primary" onClick={getData}>
        获取数据
      </Button>
    </div>
  );
}

5. 如何关闭 Mock?

在默认情况下,umijs默认开启mock

  1. 可以通过配置关闭,在.umirc.ts中:
export default {
  mock: false,
};
  1. 也可以通过环境变量临时关闭
MOCK=none umi dev

九、运行时配置

运行时配置和配置的区别是他跑在浏览器端,基于此,我们可以在这里写函数、jsx、import 浏览器端依赖等等,注意不要引入 node 依赖。

1. 配置方式

约定 src/app.tsx 为运行时配置。

2. 配置项

2.1 patchRoutes({ routes })

动态添加路由

比如在最前面添加一个 /foo 路由:

export function patchRoutes({ routes }) {
  // routes为已经注册的路由
  routes.unshift({
    path: '/foo',
    component: require('@/pages/foo').default, // 不能直接写字符串,要写一个组件
  });
}

注意:直接修改routes,不需要返回

2.2 render(oldRender: Function)

覆写 render,会在patchRoutes之前执行

比如用于渲染之前做权限校验:

import { history } from 'umi';

export function render(oldRender) {
  fetch('/api/auth').then(auth => {
    if (!auth.isLogin) {
        history.push('/login');
    }

    // 在渲染前可以进行其他操作
    // ...

    oldRender()
  });
}

也可以和2.1 patchRoutes配合使用,在render中获取动态菜单列表,使用patchRoutes进行渲染。

2.3 onRouteChange({ routes, matchedRoutes, location, action })

在初始加载和路由切换时做一些事情,在patchRoutes之后执行。

  1. 比如用于做埋点统计:
export function onRouteChange({ location, routes, action }) {
  console.log(location.pathname);
}
  1. 比如用于设置标题:
export function onRouteChange({ matchedRoutes }) {
  if (matchedRoutes.length) {
    // 配置路由时,需要配置title
    document.title = matchedRoutes[matchedRoutes.length - 1].route.title || '';
  }
}
  • 8
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值