UmiJS,中文发音为「乌米」,是可扩展的企业级前端应用框架。Umi 以路由为基础的,同时支持配置式路由和约定式路由,保证路由的功能完备,并以此进行功能扩展。然后配以生命周期完善的插件体系,覆盖从源码到构建产物的每个生命周期,支持各种功能扩展和业务需求。
npm install -g umi
umi -v
.
├── config // 配置目录
│ └── config.ts // 主配置文件
├── dist // 构建输出目录
├── mock // 模拟数据目录
│ └── app.ts|tsx // 模拟的应用数据文件
├── src // 源码目录
│ ├── .umi // Umi内部生成的临时目录
│ ├── .umi-production // Umi为生产环境生成的临时目录
│ ├── layouts // 布局组件目录
│ │ ├── BasicLayout.tsx // 基础布局组件
│ │ ├── index.less // 布局样式文件
│ ├── models // 数据模型目录
│ │ ├── global.ts // 全局数据模型
│ │ └── index.ts // 模型索引文件
│ ├── pages // 页面组件目录
│ │ ├── index.less // 页面样式文件
│ │ └── index.tsx // 主页面组件
│ ├── utils // 工具函数目录
│ │ └── index.ts // 工具函数索引
│ ├── services // 服务请求相关目录
│ │ └── api.ts // API请求文件
│ ├── app.(ts|tsx) // 主应用配置文件
│ ├── global.ts // 全局文件
│ ├── global.(css|less|sass|scss) // 全局样式文件
│ ├── overrides.(css|less|sass|scss) // 覆盖样式文件
│ ├── favicon.(ico|gif|png|jpg|jpeg|svg|avif|webp) // 网站图标文件
│ └── loading.(tsx|jsx) // 加载组件
├── node_modules // npm依赖目录
│ └── .cache // 缓存目录
│ ├── bundler-webpack // webpack打包器缓存
│ ├── mfsu // mfsu缓存
│ └── mfsu-deps // mfsu依赖缓存
├── .env // 环境变量文件
├── plugin.ts // 插件配置文件
├── .umirc.ts // Umi配置文件 (与 config/config 二选一)
├── package.json // npm包描述文件
├── tsconfig.json // TypeScript配置文件
└── typings.d.ts // TypeScript声明文件
mkdir zhufeng-umi
cd zhufeng-umi
npm init -y
mkdir src/pages
src\pages\index.js
import React, { Component } from 'react'
import { Link } from 'umi';
import styles from './index.css';
export default class componentName extends Component {
render() {
return (
<div>
<h1 className={styles.title}>首页</h1>
<Link to="/profile">个人中心</Link>
</div>
)
}
}
src\pages\index.css
.title {
background: rgb(121, 242, 214);
}
src\pages\user.js
import React from 'react';
import styles from './user.css';
export default () => {
return (
<div>
<h1 className={styles.title}>Page user</h1>
</div>
);
}
src\pages\profile.js
import React, { Component } from 'react'
import { history } from 'umi';
import styles from './profile.css';
export default class componentName extends Component {
render() {
return (
<div>
<h1 className={styles.title}>个人中心</h1>
<button onClick={()=>history.back()}>返回</button>
</div>
)
}
}
"scripts": {
"dev": "umi dev",
"build": "umi build"
}
npm run dev
npm run build
约定 src/layouts/index.js
为全局路由。返回一个 React 组件,并通过 <Outlet />
渲染嵌套路由。
src/layouts/index.js
import React, { Component } from 'react';
import { Link,Outlet } from 'umi';
export default class Layout extends Component {
render() {
return (
<div>
<ul>
<li><Link to="/" >首页</Link></li>
<li><Link to="/user">用户管理</Link></li>
<li><Link to="/profile">个人设置</Link></li>
</ul>
<div>
<Outlet />
</div>
</div>
)
}
}
config\config.js
import routes from "./routes";
export default {
routes
}
config\routes.js
export default [
{ path: '/', component: '@/pages/index.js' },
{
path: '/user',
component: '@/pages/user/index',
routes: [
{ path: 'list', component: '@/pages/user/list' },
{ path: 'add', component: '@/pages/user/add' },
{ path: 'detail/:id', component: '@/pages/user/detail/$id.js' },
],
},
{
path: '/profile',
component: '@/pages/profile.js',
wrappers: [
'@/wrappers/auth',
],
},
{ path: '/login', component: '@/pages/login.js' }
]
mock\routes.js
export default {
'GET /api/routes': [
{
path: '/foo',
component: 'Foo'
}
]
}
src\app.js
import React from 'react';
//import Foo from '@/extraRoutes/Foo';
/**
//https://umijs.org/docs/api/runtime-config#patchclientroutes-routes-
export function patchClientRoutes({ routes }) {
routes.unshift({
path: '/foo',
element: <Foo />,
});
}
*/
let extraRoutes;
export function patchClientRoutes({ routes }) {
routes.unshift(...extraRoutes);
}
export function render(oldRender) {
fetch('/api/routes')
.then((res) => {
return res.json();
})
.then((res) => {
console.log(res);
extraRoutes = res.map(({path,component})=>{
let Component = require(`@/extraRoutes/${component}`);
console.log(Component.default);
return {
path,
element: React.createElement(Component.default),
}
});
oldRender();
});
}
src\wrappers\auth.js
import {Navigate,Outlet } from 'umi';
export default () => {
const isLogin = localStorage.getItem('isLogin');
if (isLogin) {
return <Outlet/>;
} else {
return <Navigate to={{ pathname: "/login"}} state={{ from: '/profile' }}/>;
}
}
src\layouts\index.js
import React, { Component } from 'react';
import { Link,Outlet } from 'umi';
export default class Layout extends Component {
render() {
return (
<div>
<ul>
<li><Link to="/" >首页</Link></li>
<li><Link to="/user">用户管理</Link></li>
<li><Link to="/profile">个人设置</Link></li>
</ul>
<div>
<Outlet />
</div>
</div>
)
}
}
src\extraRoutes\Foo.js
import React, { Component } from 'react'
export default class componentName extends Component {
render() {
return (
<div>
Foo
</div>
)
}
}
src\pages\profile.js
import React, { Component } from 'react'
import { history } from 'umi';
import styles from './profile.css';
export default class componentName extends Component {
render() {
return (
<div>
<h1 className={styles.title}>个人中心</h1>
<button onClick={()=>history.back()}>返回</button>
</div>
)
}
}
src\pages\login.js
import React from 'react';
import { history,useLocation } from 'umi';
export default () => {
const location = useLocation();
return (
<div>
<h1 >Page login</h1>
<button onClick={() => {
localStorage.setItem('isLogin', 'true');
debugger
if (location.state && location.state.from) {
history.push(location.state.from);
}
}}>登录</button>
</div>
);
}
src\pages\index.js
import React, { Component } from 'react'
import { Link } from 'umi';
import styles from './index.css';
export default class componentName extends Component {
render() {
return (
<div>
<h1 className={styles.title}>首页</h1>
<Link to="/profile">个人中心</Link>
</div>
)
}
}
src\pages\user\index.js
import React, { Component } from 'react';
import { Link } from 'umi';
export default class extends Component {
render() {
return (
<ul>
<li><Link to="/user/detail/1">张三</Link></li>
<li><Link to="/user/detail/2">李四</Link></li>
</ul>
)
}
}
src\pages\user\list.js
import React, { Component } from 'react';
import { Link } from 'umi';
export default class extends Component {
render() {
return (
<ul>
<li><Link to="/user/detail/1">张三</Link></li>
<li><Link to="/user/detail/2">李四</Link></li>
</ul>
)
}
}
src\pages\user\add.js
import React, { Component } from 'react';
export default class extends Component {
render() {
return (
<form >
<input />
<input type="submit" />
</form>
)
}
}
src\pages\user\detail\$id.js
import React, { Component } from 'react';
export default class extends Component {
render() {
return (
<table>
<thead>
<tr>
<td>字段</td>
<td>值</td>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>张三</td>
</tr>
</tbody>
</table>
)
}
}