目录
十一、AntDesign组件库
1、react中添加class-使用第三方库classnames
import React, {PureComponent} from "react";
// 安装:npm i -S classnames
import classNames from "classnames";
export default class App extends PureComponent {
constructor(props) {
super(props);
this.state = {
isActive: true
}
}
render() {
const {isActive} = this.state
return (<div>
{/* 1、原生react中添加class方法 */}
<h2 className={"title active"}>我是标题1</h2>
<h2 className={"title" + (isActive ? " active" : "")}>我是标题2</h2>
<h2 className={["title", isActive ? "active" : ""].join(" ")}>我是标题3</h2>
{/* 2、classnames库添加class */}
<h3 className={classNames("title", "active")}>我是标题1</h3>
<h3 className={classNames({"title": true, "active": true})}>我是标题1</h3>
<h3 className={classNames(["title", {"active": true}])}>我是标题1</h3>
</div>)
}
}
2、antdesign简介
- src/index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './layout/App';
import "./styles/index.css"
import 'dayjs/locale/zh-cn';
import {ConfigProvider} from "antd"
import locale from 'antd/locale/zh_CN';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<ConfigProvider locale={locale}>
<App/>
</ConfigProvider>);
- src/layout/App.js
import React, {PureComponent} from "react";
// 安装:npm i -S antd
import {Button, DatePicker} from "antd"
// 安装图标:npm i -S @ant-design/icons
import {PoweroffOutlined} from "@ant-design/icons"
// 安装:npm i -S dayjs
import dayjs from "dayjs"
export default class App extends PureComponent {
render() {
return (<div>
<Button type={"primary"} icon={<PoweroffOutlined/>}>按钮</Button>
<DatePicker defaultValue={dayjs().add(10, "day")} allowClear={false}/>
</div>)
}
}
3、认识craco
- package.json
{
"scripts": {
"start": "craco start",
"build": "craco build",
"test": "craco test",
"eject": "react-scripts eject"
}
}
- craco.config.js
// 安装:npm i -D @craco/craco
module.exports = {};
4、自定义主题
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './layout/App';
import "./styles/index.css"
import 'dayjs/locale/zh-cn';
import {ConfigProvider} from "antd"
import locale from 'antd/locale/zh_CN';
const root = ReactDOM.createRoot(document.getElementById('root'));
// 自定义主题
root.render(<ConfigProvider
locale={locale}
theme={{
token: {
colorPrimary: '#1DA57A'
}
}}>
<App/>
</ConfigProvider>);
5、配置别名
- craco.config.js
const path = require("path")
module.exports = {
webpack: {
alias: {
// webstorm需要配置jsconfig.json才会有路径别名提示
"@": path.resolve(__dirname, "src")
}
}
};
- jsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": [
"src/*"
]
}
}
}
6、案例
- src/index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './layout/App';
import "./styles/index.css"
import {ConfigProvider} from "antd"
import locale from 'antd/locale/zh_CN';
import dayjs from "dayjs";
import 'dayjs/locale/zh-cn';
import relativeTime from "dayjs/plugin/relativeTime"
dayjs.locale("zh-cn")
// dayjs插件
dayjs.extend(relativeTime)
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<ConfigProvider locale={locale}>
<App/>
</ConfigProvider>);
- src/layout/App.js
import React, {PureComponent} from "react";
import CommonInput from "@/components/CommonInput";
import CommonItem from "@/components/CommonItem";
export default class App extends PureComponent {
constructor(props) {
super(props);
this.state = {
commentList: []
}
}
render() {
return (<>
{
this.state.commentList.map((item, index) => {
return <CommonItem comment={item}
key={item.id}
removeItem={e => this.removeComment(index)}/>
})
}
<CommonInput submitComment={this.submitComment.bind(this)}/>
</>)
}
submitComment(info) {
this.setState({
commentList: [...this.state.commentList, info]
})
}
removeComment(index) {
const newCommentList = [...this.state.commentList]
newCommentList.splice(index, 1)
this.setState({
commentList: newCommentList
})
}
}
- src/components/CommonInput.js
import React, {PureComponent} from "react";
import {Input, Button} from "antd";
import dayjs from "dayjs";
export default class CommonInput extends PureComponent {
constructor(props) {
super(props);
this.state = {
content: ""
}
}
render() {
return (<div>
<Input.TextArea rows={4}
value={this.state.content}
onChange={e => this.handleChange(e)}/>
<Button type={"primary"} onClick={e => this.addComment()}>添加评论</Button>
</div>)
}
handleChange(event) {
this.setState({
content: event.target.value
})
}
addComment() {
if (this.state.content) {
const commentInfo = {
id: dayjs().valueOf(),
avatar: "https://himg.bdimg.com/sys/portraitn/item/public.1.ad0d64c5.9sfie_WOcRvlqCxH_2MKnQ",
nickname: "斧王",
datetime: dayjs(),
content: this.state.content
}
this.props.submitComment(commentInfo)
this.setState({
content: ""
})
}
}
}
- src/components/CommonItem.js
import React, {PureComponent} from "react";
// 安装(使用过高版本会报错,与antd版本一致):npm i @ant-design/compatible
import {Comment} from "@ant-design/compatible"
import {Avatar, Tooltip} from "antd"
import {DeleteOutlined} from "@ant-design/icons";
export default class CommonItem extends PureComponent {
render() {
const {nickname, avatar, content, datetime} = this.props.comment
return (<div>
<Comment
author={<a href="/#">{nickname}</a>}
avatar={<Avatar src={avatar} alt={nickname}/>}
content={<p>{content}</p>}
datetime={<Tooltip title={datetime.format("YYYY-MM-DD")}>
<span>{datetime.fromNow()}</span>
</Tooltip>}
actions={[
<span onClick={e => this.removeItem()}><DeleteOutlined/>删除</span>
]}
/>
</div>)
}
removeItem() {
this.props.removeItem()
}
}
十二、axios库的使用
1、axios的基本使用
import React, {PureComponent} from "react";
import axios from "axios"
export default class App extends PureComponent {
constructor(props) {
super(props);
this.state = {
products: []
}
}
/**
* 1、axios:ajax i/o system
* 2、安装:npm i -S axios
* 3、请求测试网站:https://httpbin.org
* 4、使用方式:
* - axios(config)
* - axios.request(config):其它方式都是调用此种方式
* - axios.get(url[, config]):查
* - axios.delete(url[, config]):删
* - axios.head(url[, config])
* - axios.post(url[, data[, config]]):增
* - axios.put(url[, data[, config]]):改
* - axios.patch(url[, data[, config]])
*/
async componentDidMount() {
// 默认get请求
axios({
url: "https://httpbin.org/get",
params: {name: "冰龙", age: 18}
}).then(res => {
// 处理数据
// this.setState({
// products: [...this.state.products, ...res]
// })
}).catch(console.log)
const request1 = axios({
url: "https://httpbin.org/post",
data: {name: "神谕者", age: 19},
method: "post"
})
const request2 = axios.get("https://httpbin.org/get", {
params: {name: "白牛", age: 20}
})
try {
const result = await axios.post("https://httpbin.org/post", {name: "火枪", age: 21})
console.log(result)
} catch (err) {
console.log(err)
}
// Promise.all()
axios.all([request1, request2]).then(([res1, res2]) => {
console.log(res1, res2)
})
const p1 = new Promise(resolve => {
setTimeout(() => {
resolve("奇美拉")
}, 1000)
})
const p2 = new Promise(resolve => {
setTimeout(() => {
resolve("狮鹫")
}, 3000)
})
Promise.all([p1, p2]).then(res => {
console.log(res)
})
}
render() {
return (<>
APP
</>)
}
}
2、axios的配置信息
// 1、请求配置选项
// 2、响应结构信息
// 3、全局默认配置
axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
/**
* 4、自定义实例默认配置:
* - 优先是请求的config参数配置:instance({baseURL: "111"})
* - 其次是实例的default中的配置:instance.defaults.baseURL = "222"
* - 再是创建实例时的配置:const instance = axios.create({baseURL: "333"})
* - 最后全局的配置:axios.defaults.baseURL = "444"
*/
const instance = axios.create({
baseURL: 'https://api.example.com',
timeout: 5000
});
instance.defaults.headers.common['Authorization'] = AUTH_TOKEN;
3、axios拦截器
- src/layout/App.js
import React, {PureComponent} from "react";
import request from "@/utils/request"
export default class App extends PureComponent {
componentDidMount() {
request({
url: "/get",
params: {name: "小小", age: 18}
}).then(console.log)
}
render() {
return (<></>)
}
}
- src/utils/request.js
import axios from "axios"
const config = {
development: {
baseURL: "https://httpbin.org",
timeout: 5000
},
production: {
baseURL: "https://httpbin.org",
timeout: 5000
}
}
const instance = axios.create(config[process.env.NODE_ENV])
instance.interceptors.request.use(config => {
// 1、发送网络请求时,在界面中间位置显示Loading的组件
// 2、某一些请求要求用户必须携带token,如果没有携带,那么直接跳转到登录页面(router)
// 3、params/data序列化的操作
console.log("请求被拦截")
return config
}, err => {
})
instance.interceptors.response.use(res => {
return res.data
}, err => {
if (err && err.response) {
switch (err.response.status) {
case 400:
console.log("请求错误")
break;
case 401:
console.log("未授权访问")
break;
default:
console.log("其它错误信息")
}
}
return err
})
export default instance
十三、react过渡动画
1、react-transition-group使用(CSSTransition)
- src/layout/App.js
import React, {PureComponent} from "react";
// 安装:npm i -S react-transition-group
import {CSSTransition} from "react-transition-group";
import "@/styles/animation.css"
export default class App extends PureComponent {
constructor(props) {
super(props);
this.state = {
show: true
}
}
/**
* 1、官网:https://reactcommunity.org/react-transition-group/
* 2、CSSTransition执行过程中,有三个状态:appear、enter、exit
* - 开始状态:对应的类是-appear、-enter、-exit
* - 执行动画:对应的类是-appear-active、-enter-active、-exit-active
* - 执行结束:对应的类是-appear-done、-enter-done、-exit-done
* - in从false到true执行enter,in从true到false执行exit
* 3、unmountOnExit:exit动画结束时卸载节点
* 4、挂载节点时(不是false到true)执行appear动画
* 5、钩子函数
*/
render() {
return (<>
<button onClick={e => {
this.setState({show: !this.state.show})
}}>按钮
</button>
<CSSTransition in={this.state.show}
timeout={1000}
classNames={"card"}
unmountOnExit={true}
appear
onEnter={el => console.log("开始进入")}
onEntering={el => console.log("正在进入")}
onEntered={el => console.log("进入完成")}
onExit={el => console.log("开始退出")}
onExiting={el => console.log("正在退出")}
onExited={el => console.log("退出完成")}>
<div>巨牙海民</div>
</CSSTransition>
</>)
}
}
- src/styles/animation.css
.card-enter, .card-appear {
opacity: 0;
}
.card-enter-active, .card-appear-active {
opacity: 1;
transition: all 1s;
}
.card-enter-done, .card-appear-done {
opacity: 1;
}
.card-exit {
opacity: 1;
}
.card-exit-active {
opacity: 0;
transition: all 1s;
}
.card-exit-done {
opacity: 0;
}
2、react-transition-group使用(SwitchTransition)
- src/layout/App.js
import React, {PureComponent} from "react";
import {CSSTransition, SwitchTransition} from "react-transition-group";
import "@/styles/animation.css"
export default class App extends PureComponent {
constructor(props) {
super(props);
this.state = {
isOn: true
}
}
/**
* 1、SwitchTransition可以完成两个组件之间切换的炫酷动画
* - 比如我们有一个按钮需要在on和off之间切换,我们希望看到on先从左侧退出,off再从右侧进入
* - 这个动画在vue中被称之为vue transition modes
* - react-transition-group中使用SwitchTransition来实现该动画
* 2、SwitchTransition中主要有一个属性:mode,有两个值
* - in-out:表示新组件先进入,旧组件再移除
* - out-in:表示就组件先移除,新组件再进入
*/
render() {
return (<>
<SwitchTransition mode="out-in">
<CSSTransition key={this.state.isOn ? "on" : "off"}
classNames="btn"
timeout={1000}>
<button onClick={e => {
this.setState({isOn: !this.state.isOn})
}}>{this.state.isOn ? "on" : "off"}
</button>
</CSSTransition>
</SwitchTransition>
</>)
}
}
- src/styles/animation.css
.btn-enter {
opacity: 0;
transform: translateX(100%);
}
.btn-enter-active {
opacity: 1;
transform: translateX(0);
transition: all 1s;
}
.btn-exit {
opacity: 1;
transform: translateX(0);
}
.btn-exit-active {
opacity: 0;
transform: translateX(-100%);
transition: all 1s;
}
3、react-transition-group使用(TransitionGroup)
- src/layout/App.js
import React, {PureComponent} from "react";
import {CSSTransition, TransitionGroup} from "react-transition-group";
import "@/styles/animation.css"
export default class App extends PureComponent {
constructor(props) {
super(props);
const now = Date.now()
this.state = {
names: [
{id: now + 1, name: "复仇之魂"},
{id: now + 2, name: "双头龙"},
{id: now + 3, name: "发条"}
]
}
}
render() {
return (<>
<button onClick={e => this.addName()}>添加</button>
<TransitionGroup>
{
this.state.names.map(item => {
return (<CSSTransition key={item.id}
timeout={1000}
classNames="item">
<div>
{item.name}
<button onClick={e => this.removeItem(item)}>删除</button>
</div>
</CSSTransition>)
})
}
</TransitionGroup>
</>)
}
addName() {
this.setState({
names: [...this.state.names, {id: Date.now(), name: "全能骑士"}]
})
}
removeItem(row) {
this.setState({
names: this.state.names.filter(item => item.id !== row.id)
})
}
}
- src/styles/animation.css
.item-enter {
opacity: 0;
}
.item-enter-active {
opacity: 1;
transition: all 1s;
}
.item-enter-done {
opacity: 1;
color: red;
}
.item-exit {
opacity: 1;
}
.item-exit-active {
opacity: 0;
transition: all 1s;
}
.item-exit-done {
opacity: 0;
}