day0701
dva UmiJS
滴挖 乌米
很重要,公司可能会用
UmiJS
VERSION 3.X
一、介绍
1、介绍
(1)Umi是什么?
(2)什么时候不用umi?
(3)为什么不是?
2、Umi如何工作
(1)技术收敛
(2)插件和插件集
(3)配置式路由和约定式路由
(4).umi临时文件
3、快速上手
(1)环境准备
$ node -v
v10.13.0
# 国内源
$ npm i yarn tyarn -g
# 后面文档里的 yarn 换成 tyarn
$ tyarn -v
# 阿里内网源
$ tnpm i yarn @ali/yarn -g
# 后面文档里的 yarn 换成 ayarn
$ ayarn -v
(2)脚手架
$ mkdir myapp && cd myapp
$ yarn create @umijs/umi-app
# 或 npx @umijs/create-umi-app
Copy: .editorconfig
Write: .gitignore
Copy: .prettierignore
Copy: .prettierrc
Write: .umirc.ts
Copy: mock/.gitkeep
Write: package.json
Copy: README.md
Copy: src/pages/index.less
Copy: src/pages/index.tsx
Copy: tsconfig.json
Copy: typings.d.ts
(3)安装依赖
$ yarn
yarn install v1.21.1
[1/4] 🔍 Resolving packages...
success Already up-to-date.
✨ Done in 0.71s.
(4)启动项目
$ yarn start
Starting the development server...
✔ Webpack
Compiled successfully in 17.84s
DONE Compiled successfully in 17842ms 8:06:31 PM
App running at:
- Local: http://localhost:8000 (copied to clipboard)
- Network: http://192.168.12.34:8000
(5)修改配置
import { defineConfig } from 'umi';
export default defineConfig({
layout: {},
routes: [
{ path: '/', component: '@/pages/index' },
],
});
(6)部署发布
构建
$ yarn build
✔ Webpack
Compiled successfully in 17.17s
DONE Compiled successfully in 17167ms 8:26:25 PM
Build success.
✨ Done in 20.79s.
tree ./dist
./dist
├── index.html
├── umi.css
└── umi.js
本地验证
$ yarn global add serve
$ serve ./dist
┌────────────────────────────────────────────────────┐
│ │
│ Serving! │
│ │
│ - Local: http://localhost:5000 │
│ - On Your Network: http://192.168.12.34:5000 │
│ │
│ Copied local address to clipboard! │
│ │
└────────────────────────────────────────────────────┘
部署
二、Umi基础
1、目录结构
.
├── package.json
├── .umirc.ts
├── .env
├── dist
├── mock
├── public
└── src
├── .umi
├── layouts/index.tsx
├── pages
├── index.less
└── index.tsx
└── app.ts
(1)根目录
(2) /src目录
2、配置
export default {
base: '/docs/',
publicPath: '/static/',
hash: true,
history: {
type: 'hash',
},
}
(1)配置文件
config/routes.ts:
// config/routes.ts
export default [
{ exact: true, path: '/', component: 'index' },
];
config/config.ts:
// config/config.ts
import { defineConfig } from 'umi';
import routes from './routes';
export default defineConfig({
routes: routes,
});
(2)TypeScript提示
import { defineConfig } from 'umi';
export default defineConfig({
routes: [
{ path: '/', component: '@/pages/index' },
],
});
(3)本地临时配置
// .umirc.ts 或者 config/config.ts
export default { a: 1, b: 2 };
// .umirc.local.ts 或者 config/config.local.ts
export default { c: 'local' };
{
a: 1,
b: 2,
c: 'local',
}
(4)多环境多份配置
// .umirc.js 或者 config/config.js
export default { a: 1, b: 2 };
// .umirc.cloud.js 或者 config/config.cloud.js
export default { b: 'cloud', c: 'cloud' };
// .umirc.local.js 或者 config/config.local.js
export default { c: 'local' };
{
a: 1,
b: 2,
c: 'local',
}
{
a: 1,
b: 'cloud',
c: 'local',
}
3、运行时配置
(1)配置方式
(2)配置项
modifyClientRenderOpts(fn)
let isSubApp = false;
export function modifyClientRenderOpts(memo) {
return {
...memo,
rootElement: isSubApp ? 'sub-root' : memo.rootElement,
};
}
patchRoutes({ routes })
export function patchRoutes({ routes }) {
routes.unshift({
path: '/foo',
exact: true,
component: require('@/extraRoutes/foo').default,
});
}
let extraRoutes;
export function patchRoutes({ routes }) {
merge(routes, extraRoutes);
}
export function render(oldRender) {
fetch('/api/routes').then(res=>res.json()).then((res) => {
extraRoutes = res.routes;
oldRender();
})
}
render(oldRender: Function)
import { history } from 'umi';
export function render(oldRender) {
fetch('/api/auth').then(auth => {
if (auth.isLogin) { oldRender() }
else {
history.push('/login');
oldRender()
}
});
}
onRouteChange({ routes, matchedRoutes, location, action })
export function onRouteChange({ location, routes, action }) {
bacon(location.pathname);
}
export function onRouteChange({ matchedRoutes }) {
if (matchedRoutes.length) {
document.title = matchedRoutes[matchedRoutes.length - 1].route.title || '';
}
}
rootContainer(LastRootContainer, args)
export function rootContainer(container) {
return React.createElement(ThemeProvider, null, container);
}
(3)更多配置项
4、路由
单页面应用
(1)配置路由
export default {
routes: [
{ exact: true, path: '/', component: 'index' },
{ exact: true, path: '/user', component: 'user' },
],
}
path
component
exact
export default {
routes: [
// url 为 /one/two 时匹配失败
{ path: '/one', exact: true },
// url 为 /one/two 时匹配成功
{ path: '/one' },
{ path: '/one', exact: false },
],
}
routes
export default {
routes: [
{ path: '/login', component: 'login' },
{
path: '/',
component: '@/layouts/index',
routes: [
{ path: '/list', component: 'list' },
{ path: '/admin', component: 'admin' },
],
},
],
}
export default (props) => {
return <div style={{ padding: 20 }}>{ props.children }</div>;
}
redirect
export default {
routes: [
{ exact: true, path: '/', redirect: '/list' },
{ exact: true, path: '/list', component: 'list' },
],
}
wrappers
export default {
routes: [
{ path: '/user', component: 'user',
wrappers: [
'@/wrappers/auth',
],
},
{ path: '/login', component: 'login' },
]
}
import { Redirect } from 'umi'
export default (props) => {
const { isLogin } = useAuth();
if (isLogin) {
return <div>{ props.children }</div>;
} else {
return <Redirect to="/login" />;
}
}
title
(2)页面跳转
import { history } from 'umi';
// 跳转到指定路由
history.push('/list');
// 带参数跳转到指定路由
history.push('/list?a=b');
history.push({
pathname: '/list',
query: {
a: 'b',
},
});
// 跳转到上一个路由
history.goBack();
(3)hash路由
(4)Link组件
import { Link } from 'umi';
export default () => (
<div>
<Link to="/users">Users Page</Link>
</div>
);
(5)路由组件参数
export default function(props) {
console.log(props.route);
return <div>Home Page</div>;
}
(6)传递参数给子路由
import React from 'react';
export default function Layout(props) {
return React.Children.map(props.children, child => {
return React.cloneElement(child, { foo: 'bar' });
});
}
5、约定式路由
.
└── pages
├── index.tsx
└── users.tsx
[
{ exact: true, path: '/', component: '@/pages/index' },
{ exact: true, path: '/users', component: '@/pages/users' },
]
(1)动态路由
.
└── pages
└── [post]
├── index.tsx
└── comments.tsx
└── users
└── [id].tsx
└── index.tsx
[
{ exact: true, path: '/', component: '@/pages/index' },
{ exact: true, path: '/users/:id', component: '@/pages/users/[id]' },
{ exact: true, path: '/:post/', component: '@/pages/[post]/index' },
{
exact: true,
path: '/:post/comments',
component: '@/pages/[post]/comments',
},
];
(2)动态可选路由
.
└── pages
└── [post$]
└── comments.tsx
└── users
└── [id$].tsx
└── index.tsx
[
{ exact: true, path: '/', component: '@/pages/index' },
{ exact: true, path: '/users/:id?', component: '@/pages/users/[id$]' },
{
exact: true,
path: '/:post?/comments',
component: '@/pages/[post$]/comments',
},
];
(3)嵌套路由
.
└── pages
└── users
├── _layout.tsx
├── index.tsx
└── list.tsx
[
{ exact: false, path: '/users', component: '@/pages/users/_layout',
routes: [
{ exact: true, path: '/users', component: '@/pages/users/index' },
{ exact: true, path: '/users/list', component: '@/pages/users/list' },
]
}
]
(4)全局layout
.
└── src
├── layouts
│ └── index.tsx
└── pages
├── index.tsx
└── users.tsx
[
{ exact: false, path: '/', component: '@/layouts/index',
routes: [
{ exact: true, path: '/', component: '@/pages/index' },
{ exact: true, path: '/users', component: '@/pages/users' },
],
},
]
import { IRouteComponentProps } from 'umi'
export default function Layout({ children, location, route, history, match }: IRouteComponentProps) {
return children
}
(5)不同的全局layout
export default function(props) {
if (props.location.pathname === '/login') {
return <SimpleLayout>{ props.children }</SimpleLayout>
}
return (
<>
<Header />
{ props.children }
<Footer />
</>
);
}
(6)404路由
.
└── pages
├── 404.tsx
├── index.tsx
└── users.tsx
[
{ exact: true, path: '/', component: '@/pages/index' },
{ exact: true, path: '/users', component: '@/pages/users' },
{ component: '@/pages/404' },
]
(7)权限路由
import React from 'react'
function User() {
return <>user profile</>
}
User.wrappers = ['@/wrappers/auth']
export default User
import { Redirect } from 'umi'
export default (props) => {
const { isLogin } = useAuth();
if (isLogin) {
return <div>{ props.children }</div>;
} else {
return <Redirect to="/login" />;
}
}
(8)扩展路由属性
function HomePage() {
return <h1>Home Page</h1>;
}
HomePage.title = 'Home Page';
export default HomePage;
6、插件
7、页面跳转
8、HTML模板
9、Mock数据
10、环境变量
11、命令行工具
三、样式和资源文件
1、使用CSS
Umi内置支持less,不支持sass和stylus
(1)全局样式
.ant-select-selection {
max-height: 51px;
overflow: auto;
}
(2)CSS Modules
// CSS Modules
import styles from './foo.css';
// 非 CSS Modules
import './foo.css';
(3)CSS 预处理器
(4)CSS中引入第三方库
2、使用图片
四、Umi进阶
1、按需加载
2、快速刷新(Fast Refresh)
3、部署
4、使用Umi UI
5、服务端渲染(SSR)
6、mfsu(Module Federation Speed Up)
TS TypeScript
https://lurongtao.gitee.io/felixbooks-typescript/
一、TS简介
1.什么是TypeScript
2.安装TypeScript
(1)在全局环境里安装TS
npm install -g typescript
(2)用 tsc 命令编译 .ts 文件
app.ts 文件:
let title: string = 'TypeScript标题'
在命令行里输入以下命令都可以将.ts文件编译为.js文件:
tsc ./src/app.ts --outFile ./dist/app.js
tsc ./src/* --outDir ./dist --watch
(3)tsconfig.json 配置文件
在命令行里输入 tsc --init
命令,创建一个 tsconfig.json 文件,在此配置文件里修改:
"outDir": "./dist",
"rootDir": "./src"
3.五分钟了解TypeScript
(1)构建第一个TypeScript文件
function greeter(person: string) {
return "Hello, " + person
}
let user = "Jane User"
console.log(greeter(user))
(2)类型注解
function greeter(person: string) {
return "Hello, " + person
}
let user = [0, 1, 2]
console.log(greeter(user))
Argument of type 'number[]' is not assignable to parameter of type 'string'.
管杀不管埋
(3)接口
interface Person {
firstName: string
lastName: string
}
function greeter(person: Person) {
return "Hello, " + person.firstName + " " + person.lastName
}
let user = { firstName: "Jane", lastName: "User" }
console.log(greeter(user))
(4)类
class Student {
fullName: string
constructor(public firstName, public middleInitial, public lastName) {
this.fullName = firstName + " " + middleInitial + " " + lastName
}
}
interface Person {
firstName: string
lastName: string
}
function greeter(person: Person) {
return "Hello, " + person.firstName + " " + person.lastName
}
let user = new Student("Jane", "M.", "User")
console.log(greeter(user))
二、TS基础
1.基础类型-基础
(1)介绍
(2)布尔值
et isDone: boolean = false
(3)数字
let decLiteral: number = 6
(4)字符串
let from: string = "JavaScript"
from = "TypeScript"
let surname: string = `Felix`
let age: number = 37
let sentence: string = `Hello, my name is ${ surname }.
I'll be ${ age + 1 } years old next month.`
(5)数组
let list: number[] = [1, 2, 3]
let list: Array<number> = [1, 2, 3]
(6)元组Tuple
// 声明一个元组类型 x
let x: [string, number]
// 初始化 x
x = ['hello', 10] // OK
// 无效的初始值
x = [10, 'hello'] // Error
console.log(x[0].substr(1)) // OK
console.log(x[1].substr(1)) // Error, 'number' 不存在 'substr' 方法
x[3] = "world" // Error, '[string, number]' 未定义第 3 个元素的类型.
console.log(x[5].toString()) // Error, '[string, number]' 未定义第 5 个元素的类型.
(7)枚举
enum Color {Red, Green, Blue}
let c: Color = Color.Green
enum Color {Red = 1, Green = 2, Blue = 4}
let c: Color = Color.Green
enum Color {Red = 1, Green, Blue}
let colorName: string = Color[2]
console.log(colorName) // 'Green'
(8)any
let notSure: any = 4
notSure = "maybe a string instead" // OK 赋值了一个字符串
notSure = false // OK 赋值了一个布尔值
let notSure: any = 4
notSure.ifItExists() // okay, ifItExists函数在运行时可能存在
notSure.toFixed() // okay, toFixed 函数存在 (在编译时不做检查)
let list: any[] = [1, true, "free"]
list[1] = 100
(9)void
function echo(): void {
console.log('TypeScript')
}
let unusable: void = undefined
let greeting: void = 'hello world' // void 类型不能赋值为字符串
2.函数
3.接口
ts两种接口???
数据类型的和后端的?
鸭子模型:带黄毛就行
java和ts都是单继承,一个儿子只有一个父亲
接口用来实现多继承
4.类
5.类和接口
6.泛型
(1)简单的例子
function createArray(length: number, value: any): Array<any> {
let result = []
for (let i = 0; i < length; i++) {
result[i] = value
}
return result
}
createArray(3, 'x'); // ['x', 'x', 'x']
function createArray<T>(length: number, value: T): Array<T> {
let result: T[] = []
for (let i = 0; i < length; i++) {
result[i] = value
}
return result
}
createArray<string>(3, 'x'); // ['x', 'x', 'x']
function createArray<T>(length: number, value: T): Array<T> {
let result: T[] = []
for (let i = 0; i < length; i++) {
result[i] = value
}
return result
}
createArray(3, 'x') // ['x', 'x', 'x']
(2)多个类型参数
function swap<T, U>(tuple: [T, U]): [U, T] {
return [tuple[1], tuple[0]]
}
swap([7, 'seven']) // ['seven', 7]
(3)泛型约束
function loggingIdentity<T>(arg: T): T {
console.log(arg.length)
return arg
}
// Property 'length' does not exist on type 'T'.
interface Lengthwise {
length: number
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length)
return arg
}
interface Lengthwise {
length: number
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length)
return arg
}
loggingIdentity(7)
// Argument of type '7' is not assignable to parameter of type 'Lengthwise'.
类型扩展
管杀不管埋
ts验证报错js也能运行
(4)泛型接口
定义函数类型:参数类型,返回类型
interface SearchFunc {
(source: string, subString: string): boolean
}
let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
return source.search(subString) !== -1
}
interface CreateArrayFunc {
<T>(length: number, value: T): Array<T>
}
let createArray: CreateArrayFunc;
createArray = function<T>(length: number, value: T): Array<T> {
let result: T[] = []
for (let i = 0; i < length; i++) {
result[i] = value
}
return result
}
createArray(3, 'x') // ['x', 'x', 'x']
interface CreateArrayFunc<T> {
(length: number, value: T): Array<T>
}
let createArray: CreateArrayFunc<any>
createArray = function<T>(length: number, value: T): Array<T> {
let result: T[] = []
for (let i = 0; i < length; i++) {
result[i] = value
}
return result
}
createArray(3, 'x'); // ['x', 'x', 'x']
(5)泛型类
class GenericNumber<T> {
zeroValue: T
add: (x: T, y: T) => T
}
let myGenericNumber = new GenericNumber<number>()
myGenericNumber.zeroValue = 0
myGenericNumber.add = function(x, y) { return x + y }
三、TS进阶
1.基础类型-高级
2.Symbols
3.迭代器和生成器
4.装饰器
5.声明文件
6.声明合并
7.变量声明
react中使用ts
https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/hooks/