一、react基础
1.进程
![](https://i-blog.csdnimg.cn/direct/e810e23a9cb9422bb6043a394aba228f.png)
2、优势
![](https://i-blog.csdnimg.cn/direct/681b03a926af411a9a0aff06e2d43470.png)
封装成一个库,组件化开发更加方便
跨平台主要是react native等可以来写移动端如android,ios等
丰富生态:可以在很多浏览器用
3、市场
![](https://i-blog.csdnimg.cn/direct/afc5f9d272094074a7e1a1688ca43e34.png)
4、搭建脚手架
![](https://i-blog.csdnimg.cn/direct/4c002ad2331d4b518d3ea276d3819677.png)
npx create-react-app react-basic
npm start后仍然可能会报错
![](https://i-blog.csdnimg.cn/direct/39d729bb90a845728a04b608a6cacca5.png)
解决办法,在index.js中把这两行注释掉
![](https://i-blog.csdnimg.cn/direct/a42a57e8810a4c4286efd40bbe49a838.png)
![](https://i-blog.csdnimg.cn/direct/b9770626f1c748ffb8bc8a032269f71d.png)
认识目录
核心依赖(右边两个react)
![](https://i-blog.csdnimg.cn/direct/b15df1388adc489ea504eef6c21dddc1.png)
去除非必要
除了app.js和index.js其他全干掉
index.js
![](https://i-blog.csdnimg.cn/direct/786a622747e7498b8d4eb11bb73e94fa.png)
app.js
![](https://i-blog.csdnimg.cn/direct/71189c9158444222b125a462a006916a.png)
重新启动测试
npm start
![](https://i-blog.csdnimg.cn/direct/f0855afaf4314f07be76cb9f398fa3f8.png)
运行原理:
![](https://i-blog.csdnimg.cn/direct/6d528127e07b46e2b77d2ea56d3ad119.png)
![](https://i-blog.csdnimg.cn/direct/b4bdede038854986b7a7ac81371f1e1a.png)
![](https://i-blog.csdnimg.cn/direct/2004d2178d8041d48db0c5478060612f.png)
总结
创建->清理
![](https://i-blog.csdnimg.cn/direct/7ccd0876991443d085579091a0d40a96.png)
5、JSX
![](https://i-blog.csdnimg.cn/direct/d4fe6d21af214da4b1235a0901ae4fa4.png)
本质
![](https://i-blog.csdnimg.cn/direct/a69dea52c8794ef89c9bc07558588897.png)
工具编译测试
Babel · Babel,点击上面的try it out,然后勾选左边的react就可以了
![](https://i-blog.csdnimg.cn/direct/86be69b46b234fb5abfcf838679ac85f.png)
也就是说,JSX是浏览器不认可的格式,需要通过babel编译器转换成js
高频场景
![](https://i-blog.csdnimg.cn/direct/0d09abcd9cb9421781811bba8a06b90f.png)
![](https://i-blog.csdnimg.cn/direct/957a36c083be46cab11c2939409a80e8.png)
const count = 1000
function getName(){
return(
'john'
)
}
function App() {
return (
<div className="App">
this is my first react app
{'this is message'}
{count}
{getName()}
{new Date().getDate()}
<div style={{color:'red'}}>this is div</div>
</div>
);
}
解释:外面的括号(外层)是识别表达式,内层是对象结构
注意
![](https://i-blog.csdnimg.cn/direct/7689eb65c20a4456b8d4703963f4d962.png)
渲染列表
![](https://i-blog.csdnimg.cn/direct/86878a94badf45f0ae2ca9261161ee12.png)
总结
![](https://i-blog.csdnimg.cn/direct/616bb596ce2841399dc50e798743a160.png)
const list = [
{id:1001,name:'react'},
{id:1002,name:'angular'},
{id:1003,name:'vue'}
]
function App() {
return (
<div className="App">
<ul>
{list.map(item=><li key={item.id}>{item.name}</li>)}
</ul>
</div>
);
}
export default App;
条件渲染
简单情况
![](https://i-blog.csdnimg.cn/direct/e1378584fc744141bba452f5c0b7f594.png)
![](https://i-blog.csdnimg.cn/direct/5171502f497d4842bf572d205b1a7a14.png)
复杂情况
一个页面三种图片展示方式
![](https://i-blog.csdnimg.cn/direct/ce036b0f950d49b7bb7b941a0d87b839.png)
事件绑定(交互)
![](https://i-blog.csdnimg.cn/direct/55eb60edaf4743d7a652675ef1f2416e.png)
获取事件参数e
![](https://i-blog.csdnimg.cn/direct/fb744ab89dcd418fb8e8df134ec0730c.png)
自定义参数(要用函数引用)
![](https://i-blog.csdnimg.cn/direct/dd8a5e95bf68433fa730fb81b77059db.png)
两个都要
![](https://i-blog.csdnimg.cn/direct/5a2be6aa874b4629b8c623cd2825937c.png)
6、组件
![](https://i-blog.csdnimg.cn/direct/6c986365b9c54cc2bcfb1ba17740123a.png)
![](https://i-blog.csdnimg.cn/direct/003b77c0548a4be591c9f9e48ad7a923.png)
![](https://i-blog.csdnimg.cn/direct/8d09290e28dc4c468425c54dac9be9ec.png)
所谓的组件其实就是函数,可以用function也可以用箭头函数声明,只要首字母是大写就可以。
7、useState
![](https://i-blog.csdnimg.cn/direct/091d7cc5975e4832a61a6d70697d5427.png)
![](https://i-blog.csdnimg.cn/direct/8da2edea12bd476f970dcc4695c9611f.png)
状态不可变
![](https://i-blog.csdnimg.cn/direct/1e091cc6de004b44b1acb9cca2e5afe9.png)
修改对象状态
![](https://i-blog.csdnimg.cn/direct/ab2b611a5d2a4ee283c002c71e0282f5.png)
![](https://i-blog.csdnimg.cn/direct/4099dbdb0539439194aa23e22abdc2e0.png)
拓展:看看官方文档数组要怎么变化
8、组件样式变化
![](https://i-blog.csdnimg.cn/direct/7b1570e2436b4ab88e3a14137b023241.png)
1、行内样式
![](https://i-blog.csdnimg.cn/direct/9b5611e2f12f409fb84f76f7772ac190.png)
2、类名
![](https://i-blog.csdnimg.cn/direct/b2c85082e516439abc1ca75519d035ab.png)
9、B站评论案例
![](https://i-blog.csdnimg.cn/direct/38724262d54543dc896801cbb0a78cfe.png)
渲染
![](https://i-blog.csdnimg.cn/direct/4b95c2e8e0b64d6a80d90dfdf245b7b6.png)
这堆要放在commentList的map循环里面
删除
![](https://i-blog.csdnimg.cn/direct/917d4b998621466e8942399aa7b5c93b.png)
![](https://i-blog.csdnimg.cn/direct/8238e5e6eb884f35a218e2efca6e49e3.png)
![](https://i-blog.csdnimg.cn/direct/1ede6955d9eb408384c816800f59cb69.png)
思路是传一个id进去函数,然后用过滤器过滤掉id相等的那个人
切换功能
![](https://i-blog.csdnimg.cn/direct/409d158dac47487690c6316280081023.png)
![](https://i-blog.csdnimg.cn/direct/c55440e314b14443abdad7cfff718787.png)
![](https://i-blog.csdnimg.cn/direct/f7125021692c4a3fb04913b7ddba5426.png)
![](https://i-blog.csdnimg.cn/direct/dccd81a9001747799d5f4bd3652420a8.png)
思路:先准备一个列表,遍历出最热和最新,设置一个动态state,点击就传type给函数,然后顺便修改这个state,高亮显示就是动态类名,判断这个state和遍历的item一不一样。
![](https://i-blog.csdnimg.cn/direct/a911ef9cc39a40aabba6e411da841d9b.png)
排序
![](https://i-blog.csdnimg.cn/direct/7227a14eb9514a92b42e05f55a6e52d8.png)
安装lodash,主要用他的order功能
npm i lodash
![](https://i-blog.csdnimg.cn/direct/845a8086d33c4f7da4e3277241fbc008.png)
引入横杠
![](https://i-blog.csdnimg.cn/direct/36e1edd9722c4a29b169db73bddfdf89.png)
![](https://i-blog.csdnimg.cn/direct/d35639ecb5a64d5f9dcb31388390bb75.png)
解释:三个字段,第一个是列表,第二个是针对哪个type,第三个是排序方式
![](https://i-blog.csdnimg.cn/direct/fe94075167334e21bab736074077c5aa.png)
改进
让一开始进去就是按最热排序,有默认排序
修改前
![](https://i-blog.csdnimg.cn/direct/374f06bf9d14441db70e99b374af7d54.png)
修改后
![](https://i-blog.csdnimg.cn/direct/b2baba208d024e25ae96fd3cddfec27b.png)
10、classnames优化类名
![](https://i-blog.csdnimg.cn/direct/40beaeaeaf9945ad8aee85f4e1797872.png)
图里面那种本质还是字符串拼接的模板字符串
安装包
npm i classnames
import
![](https://i-blog.csdnimg.cn/direct/2aec158bd9e047b69d49f3318a731b63.png)
![](https://i-blog.csdnimg.cn/direct/dea08fd68fdd4699a3e68268b5c641da.png)
11、受控表单绑定
![](https://i-blog.csdnimg.cn/direct/bbd9047390874e4fbf9ebb434a473c54.png)
![](https://i-blog.csdnimg.cn/direct/fd0cabcf5e224db5a026620e379ee203.png)
12、react中获取dom
![](https://i-blog.csdnimg.cn/direct/9c237ddb2d484d408d49d1cb154dd9f8.png)
![](https://i-blog.csdnimg.cn/direct/78c3a98d7fea4953901578630fad485a.png)
可以用dir查看有哪些属性
![](https://i-blog.csdnimg.cn/direct/dd71a33abb524de79f620cbba07271c7.png)
13、发布评论
![](https://i-blog.csdnimg.cn/direct/b926c184490943f7804ed2740e19f559.png)
1、获取评论内容
![](https://i-blog.csdnimg.cn/direct/a95aa876ef9e4aebb08e6b787d7e39ad.png)
![](https://i-blog.csdnimg.cn/direct/f5fff4a14fe24293bd9a26c339958446.png)
2、点击发布触发回调函数
![](https://i-blog.csdnimg.cn/direct/f490c7ab323a4d32b7ec3ad905450ddd.png)
![](https://i-blog.csdnimg.cn/direct/5ac985e5f29247039f5489b3819577f1.png)
本质是修改commentList,先展开,后面再拓展进去(格式要一致),content改为动态的
3、优化
![](https://i-blog.csdnimg.cn/direct/76a3f61cfdce43618a52b33a5d19c195.png)
安装uuid
npm i uuid
用法
![](https://i-blog.csdnimg.cn/direct/102912b98515410a8bf071b08c88d709.png)
import {v4 as uuidv4} from 'uuid';
day.js
![](https://i-blog.csdnimg.cn/direct/01e85558da284261b26ef4b613bcceae.png)
import dayjs from 'dayjs';
![](https://i-blog.csdnimg.cn/direct/9f820bd71b5147ddb953d490918a5996.png)
主要观察rpid,ctime
13、清空内容并聚焦案例
当发布完评论后就要这样
![](https://i-blog.csdnimg.cn/direct/c5e07d290aa9457381c8d4aaa88872b7.png)
1、清空内容
![](https://i-blog.csdnimg.cn/direct/53982655e8b3417d9365e4c1d73db611.png)
2、聚焦
先创建ref实例,然后绑定到input,最后调用focus方法即可
![](https://i-blog.csdnimg.cn/direct/4203c374fb174c829a211a6ac54e91fb.png)
![](https://i-blog.csdnimg.cn/direct/f72025288305436080b269899d9bc4a9.png)
调用current.focus()即可
![](https://i-blog.csdnimg.cn/direct/9e3f9606dc964890bf1ba404dd3510b2.png)
14、组件通信
![](https://i-blog.csdnimg.cn/direct/6b93969534674d24954f5016bed60540.png)
父传子
![](https://i-blog.csdnimg.cn/direct/ec31a42717e148cfab5769634bfb1dbf.png)
![](https://i-blog.csdnimg.cn/direct/571418184dcd45a894d661d72491523f.png)
function Son(props){
return <div>this is son,{props.name}</div>
}
function App() {
const name = "this is father"
return (
<div className="App">
<Son name={name}></Son>
</div>
);
}
export default App;
![](https://i-blog.csdnimg.cn/direct/4712bca35b2b48bf9f7d84ba32287974.png)
![](https://i-blog.csdnimg.cn/direct/7c01f288468a4220a951ca973fa78548.png)
props说明
![](https://i-blog.csdnimg.cn/direct/2ea4baca7fe640a19e600392a26725a6.png)
这里修改会报错,因为props是只读属性
![](https://i-blog.csdnimg.cn/direct/3e128d31a9b4475b826a79e06a990426.png)
children说明
![](https://i-blog.csdnimg.cn/direct/15026f4295fc4a869888b8796d4d3cf2.png)
![](https://i-blog.csdnimg.cn/direct/2d435089bce2483d986ca8ea6f350481.png)
子传父
![](https://i-blog.csdnimg.cn/direct/256eda0558344a9c905cc142c6fb9195.png)
影响视图变化的是状态数据
![](https://i-blog.csdnimg.cn/direct/555711969f914efd8ce4d49f627e9ab2.png)
兄弟组件通信
![](https://i-blog.csdnimg.cn/direct/2625aac7d5a04d039760613837b3abd0.png)
import {useState} from "react";
function A({onGetAMsg}){
const name = "this is A"
return (
<div>
我是A组件
<button onClick={()=>onGetAMsg(name)}>send</button>
</div>
)
}
function B({name}){
return(
<div>
我是B组件
{name}
</div>
)
}
function App() {
const [name,setName] = useState(null)
const getAMsg = (msg)=>{
setName(msg)
}
return (
<div className="App">
<A onGetAMsg={getAMsg}/>
<B name={name}/>
</div>
);
}
export default App;
跨层组件通信
![](https://i-blog.csdnimg.cn/direct/7396849b84c249678c1d2ac6309ff1ed.png)
![](https://i-blog.csdnimg.cn/direct/6513670902d348d2bc31d799204134fd.png)
![](https://i-blog.csdnimg.cn/direct/d138b110d5434f6391d56f114e10acaf.png)
15、useEffect
![](https://i-blog.csdnimg.cn/direct/4a50a25543884994af29de9a8d5a0ba3.png)
![](https://i-blog.csdnimg.cn/direct/e8aa2e4aab1b473f9d24de0ae4f0f0bc.png)
我们主要关注是否有请求并且只请求一次。
依赖项参数说明
![](https://i-blog.csdnimg.cn/direct/f062aec76203484bb47c9f18783520cc.png)
第一种情况
![](https://i-blog.csdnimg.cn/direct/e7980ab7c9b24a99b559dcd9e575bc5e.png)
事实也确实是这样,组件初始化和更新时都会执行一次
第二种情况
![](https://i-blog.csdnimg.cn/direct/1391c009d0424552860316b46790dabd.png)
这里只执行一次
第三种情况
![](https://i-blog.csdnimg.cn/direct/a685cc15960b432985fcd20dfc4bb00a.png)
看起来和第一种情况差不多,实则不然,第一种情况不管什么组件更新都会执行一次,而这里只有count变化才执行一次。
清除副作用
![](https://i-blog.csdnimg.cn/direct/932a10cf3c474362a6c9284963fc84a5.png)
![](https://i-blog.csdnimg.cn/direct/b089f9cba18646c788b9c36ccdd00942.png)
import {useEffect, useState} from "react";
function Son(){
useEffect(() => {
const timer = setInterval(()=>{
console.log("定时器执行中")
},1000)
return () => {
clearInterval(timer)
}
}, []);
return <div>this is son</div>
}
function App() {
const [show, setShow] = useState(true)
return (
<div className="App">
{show && <Son/>}
<button onClick={()=>setShow(false)}>卸载Son组件</button>
</div>
);
}
export default App;
16、自定义hook函数
![](https://i-blog.csdnimg.cn/direct/13e25676509a4e248d80d1bc5745f627.png)
不封装直接实现
![](https://i-blog.csdnimg.cn/direct/a7cfb0e561be4dbfb6387b53ffe1070b.png)
封装自定义Hook实现
![](https://i-blog.csdnimg.cn/direct/99592f6bf649407c925ecf33911f45bd.png)
抽象实现的通用逻辑
![](https://i-blog.csdnimg.cn/direct/11ee8dc2580b4527ab2a6328569a8c21.png)
17、ReactHooks使用规则
![](https://i-blog.csdnimg.cn/direct/9e22ce67503145c8b9df03181de8981f.png)
第一种错误
![](https://i-blog.csdnimg.cn/direct/8df4f2e680a040f2be9490fa41322773.png)
第二种错误
![](https://i-blog.csdnimg.cn/direct/acaf265d328642dab6f1748d70251a0e.png)
18、优化B站评论
![](https://i-blog.csdnimg.cn/direct/4d14809f67624473a2de5655119237ec.png)
需求1
![](https://i-blog.csdnimg.cn/direct/5f933119f51d48dea9350ef427315b00.png)
json-sever
![](https://i-blog.csdnimg.cn/direct/0d2f93985ac34c10b884febda23ac8e9.png)
npm i json-sever -D
根目录创建db.json
![](https://i-blog.csdnimg.cn/direct/702ec4ee2e6f49b7b4ff5125bda91d27.png)
复制静态数据过来
![](https://i-blog.csdnimg.cn/direct/7280647da33542a1baa3ad16d8fafcb1.png)
pages.json添加serve
![](https://i-blog.csdnimg.cn/direct/9f700b4a6e83427dbf4ced23c2ac4701.png)
npm run serve启动
npm run serve
有笑脸就是成功
![](https://i-blog.csdnimg.cn/direct/ead34b11f9ff43289f2df0d29ec26a7a.png)
可以尝试请求这个地址
![](https://i-blog.csdnimg.cn/direct/f02eecb87850423ab01c3b889854030d.png)
打开就是模拟get请求
![](https://i-blog.csdnimg.cn/direct/4813f704460441ad89c9e912c314d423.png)
axios
npm i axios
从后台获取数据
先初始化一个动态数组准备接收
![](https://i-blog.csdnimg.cn/direct/95f6f961398349218238490609713fe5.png)
先在useEffect里编写函数逻辑,再来调用函数
需求2
![](https://i-blog.csdnimg.cn/direct/ab32872d6a2344aa9a99f434c19c9dc2.png)
封装函数
把上一步编写的逻辑都放到hook函数里面
![](https://i-blog.csdnimg.cn/direct/9f0a82de88794ff48003ba16173a5062.png)
App组件调用
![](https://i-blog.csdnimg.cn/direct/26a462959ded4f80964b8885be79c525.png)
需求3
![](https://i-blog.csdnimg.cn/direct/0f037294287646aa98c7fb21d1450900.png)
封装Item组件
![](https://i-blog.csdnimg.cn/direct/f447ac16751c4707ac80711fb8fc35cf.png)
![](https://i-blog.csdnimg.cn/direct/b3f698333d3247929a943e58500d77d1.png)
去掉key
![](https://i-blog.csdnimg.cn/direct/b5aeb7d518e349a3b25f9f99252f5ff2.png)
![](https://i-blog.csdnimg.cn/direct/73550c32cca54113ac3129b35a6c93f8.png)
这里会报错,先把功能去掉
![](https://i-blog.csdnimg.cn/direct/7ed8bc8e61fe4fceadd9329cfd876cca.png)
![](https://i-blog.csdnimg.cn/direct/632c45879de7426b801bb5b8a2532038.png)
封装删除功能(子组件调用父组件 / 父传子)
![](https://i-blog.csdnimg.cn/direct/80d061e2f34c4c888e4a8ced5512cbb9.png)
父传子把功能传递下去(onDel那里)
![](https://i-blog.csdnimg.cn/direct/4f2c3efda15643b5b32c5443c4e5f740.png)
接收一下
![](https://i-blog.csdnimg.cn/direct/3781251ffbdc430ba1f9b0120a696c6e.png)
重新调用
![](https://i-blog.csdnimg.cn/direct/2a1982c7fd494e70b30b3d04a6289154.png)
至此,我们通过组件抽象的方式实现了小组件的封装
19、Redux
![](https://i-blog.csdnimg.cn/direct/c242468314124a0abc1515f0ed675b49.png)
快速体验(计数器)
模版
![](https://i-blog.csdnimg.cn/direct/168b1c4cff2e49cdac0ab818208bae30.png)
![](https://i-blog.csdnimg.cn/direct/fd1f3c2e77aa467d893c55621337f611.png)
![](https://i-blog.csdnimg.cn/direct/70f05859f8864e1793b48004396fba22.png)
最后一步
![](https://i-blog.csdnimg.cn/direct/5146358fead74e99bab967c5f6f22c94.png)
流程梳理
![](https://i-blog.csdnimg.cn/direct/8d9417a193a64fe19e4c6983c32d0a23.png)
20、react-redux
![](https://i-blog.csdnimg.cn/direct/e74fa541dbe642b7b68275f04884adc5.png)
配置基础环境
![](https://i-blog.csdnimg.cn/direct/69148ed3c2234b9d987e3ba9edbd6e4f.png)
store目录结构设计
![](https://i-blog.csdnimg.cn/direct/c1dbfeb8e0d34142adf6d840c36754f7.png)
跟着创建目录先
21、用redux继续实现counter案例
整体路径熟悉
![](https://i-blog.csdnimg.cn/direct/e751578c31c2491bbfa6ccd5927ee163.png)
使用Reacttoolkit创建counterStore
![](https://i-blog.csdnimg.cn/direct/7f9f93d5572c4e66b3c786997754ce02.png)
![](https://i-blog.csdnimg.cn/direct/c1771f399088446eaa7812d29d68a81e.png)
使用中间件react-redux连接,为React注入store
下面是在根目录的index.js中操作的哦
![](https://i-blog.csdnimg.cn/direct/92314dd476934a0b91c17d05c2385c3b.png)
![](https://i-blog.csdnimg.cn/direct/ebddddc5119443808fb32f7081895261.png)
react中使用store数据
useSelector
![](https://i-blog.csdnimg.cn/direct/269ea6a5654f4c4cbbbf620a3bd4860d.png)
react中修改store数据
useDispatch
![](https://i-blog.csdnimg.cn/direct/0284d3a441cf47febbb48cbc108e99d2.png)
这里还要引入store里的actions对象,然后通过中间件的useDispatch提交
![](https://i-blog.csdnimg.cn/direct/f2ba142f512d4c1b9070cdfadb1fa872.png)
总结
![](https://i-blog.csdnimg.cn/direct/d168a22489994351b6d18d44ff615ed2.png)
22、提交action传参
需求
![](https://i-blog.csdnimg.cn/direct/8775dff467d44e12857d5549d3ecabaf.png)
实现
![](https://i-blog.csdnimg.cn/direct/36dbb1be53ae476e8ae0371bfee8aaa8.png)
完整代码
![](https://i-blog.csdnimg.cn/direct/98fad8fd564e478e991c6322e1fcc543.png)
原理:跟action对象的payload有关
23、react-redux异步操作
需求理解:跟之前的没什么变化,只是多了异步修改
![](https://i-blog.csdnimg.cn/direct/a7f10677278c41d385ebdba194bd7947.png)
异步操作样板代码
![](https://i-blog.csdnimg.cn/direct/dfad218c938e492c86ab314c7b894971.png)
实际代码,重新创建channelStore.js
![](https://i-blog.csdnimg.cn/direct/74cdc32f29aa4cbf9a8214fcbd6b9179.png)
导出reducer
![](https://i-blog.csdnimg.cn/direct/d54b4a1a27544a08b3cac52242871823.png)
![](https://i-blog.csdnimg.cn/direct/1235eff65bd94c47b8b587fdda650704.png)
24、redus调试-devtools
安装扩展程序
![](https://i-blog.csdnimg.cn/direct/06cf21d2ec764384a02f38c4115c7969.png)
![](https://i-blog.csdnimg.cn/direct/7a1697ced06545629629960dce7e3bb1.png)
重启浏览器就可以
25、美团案例
1、点击左边列表,右边列表也会渲染
2、点击+号下面会有高亮显示
3、清除购物车
![](https://i-blog.csdnimg.cn/direct/92cb1dbcc2d845c8a5a7ba85f23fb9e9.png)
准备工作
![](https://i-blog.csdnimg.cn/direct/63a7e5c840884d5aa1f4d05cd6bdf702.png)
分类和商品列表
![](https://i-blog.csdnimg.cn/direct/3f056aff53e64ced9d5eb701ce7a5ee6.png)
![](https://i-blog.csdnimg.cn/direct/2cbd6ae6ba304ff08137f7355a4902e3.png)
启动项目
npm run start
npm run serve
创建store实例
![](https://i-blog.csdnimg.cn/direct/e70789518c184e3080975cb7b92c3fea.png)
异步获取
![](https://i-blog.csdnimg.cn/direct/5358c8e2b25f475f929952575a9f5764.png)
导出
![](https://i-blog.csdnimg.cn/direct/769529dbdfd14fa3be2daa173b1e8106.png)
modules的index.js引入
![](https://i-blog.csdnimg.cn/direct/bfbd546907034551a4ee584866ce7cec.png)
根目录的index.js引入
![](https://i-blog.csdnimg.cn/direct/c1ddebecb36e4a958b7e216d19999bb6.png)
触发action并且渲染数据
![](https://i-blog.csdnimg.cn/direct/be08501bc18a43f99482727d35902ccf.png)
用redux工具查看
![](https://i-blog.csdnimg.cn/direct/96c6e13adb4a490883a8825bc39c96c6.png)
渲染列表
![](https://i-blog.csdnimg.cn/direct/a734633785a04d69a4b05b09a487f21e.png)
点击分类激活交互实现
![](https://i-blog.csdnimg.cn/direct/21664156b9574b51a4142b6c63a4bc59.png)
点击背景会变白
redux编写
![](https://i-blog.csdnimg.cn/direct/8913cd8d17bf4944b95e3a9d3649c846.png)
![](https://i-blog.csdnimg.cn/direct/88c1cddc37124e33a2ced40d8b4a430e.png)
解构出来并export出去
![](https://i-blog.csdnimg.cn/direct/4a0026d0a8294d91838869d5d4ff4863.png)
Menu组件的index.js引入方法和使用dispatch
![](https://i-blog.csdnimg.cn/direct/7ac0471fae934709852c540564e36fb5.png)
redux工具调试查看
![](https://i-blog.csdnimg.cn/direct/235686148a944e3d8b9f43e0954f3c6a.png)
引入activeIndex
![](https://i-blog.csdnimg.cn/direct/bf24d31bf14e4b7aaa5e7d4e644fcdb2.png)
classNames编写
![](https://i-blog.csdnimg.cn/direct/7e47dae2676c437395cbe41c8671561f.png)
商品列表切换显示(视图控制)
![](https://i-blog.csdnimg.cn/direct/2e8b4f8c0d944b18a5fd3c35437b6ebb.png)
App.js引入activeIndex
![](https://i-blog.csdnimg.cn/direct/1b42757b89344761b906c5e8fd5f24f7.png)
![](https://i-blog.csdnimg.cn/direct/de44c96295774be9a8d471d6e7d00090.png)
添加购物车实现
思路
![](https://i-blog.csdnimg.cn/direct/33c1eb98efca4826af50e9df088928ca.png)
redux编写
编写modules的state
![](https://i-blog.csdnimg.cn/direct/ca6359b7fa914f5da405e5b416bc4112.png)
编写reducer
![](https://i-blog.csdnimg.cn/direct/89f9016c142e4460ac17ddf593f0f05b.png)
export导出
![](https://i-blog.csdnimg.cn/direct/3d42803d42b64922a3e572c31425d2a9.png)
编写foodsCart组件
引入方法
![](https://i-blog.csdnimg.cn/direct/e79a13e1fe0246bfa6d2b3d003c5aec7.png)
引入dispatch
![](https://i-blog.csdnimg.cn/direct/ae05841d4b504e7c8b0153d8df1e9dcc.png)
传入对象
![](https://i-blog.csdnimg.cn/direct/a62c4274622942d19142c61d81743940.png)
使用redux工具测试
![](https://i-blog.csdnimg.cn/direct/2f089d81bf4147e4860395e9a455c202.png)
统计区域功能实现
![](https://i-blog.csdnimg.cn/direct/422969c54c5044fba608e2c8374fe954.png)
思路
![](https://i-blog.csdnimg.cn/direct/3af5d3b9ab684fd2888a1bee3ba50e1a.png)
cart组件取到carList长度渲染
![](https://i-blog.csdnimg.cn/direct/33c8195dbc224368a935baf951100821.png)
![](https://i-blog.csdnimg.cn/direct/fcc4c582630d4603abf537dfca2822a7.png)
成功实现
计算总价(reduce方法和toFixed)
![](https://i-blog.csdnimg.cn/direct/bca0917d23914c9aad61a2b71ac29679.png)
![](https://i-blog.csdnimg.cn/direct/ebd61daad0ff4bc5a73aea6dea448c69.png)
高亮(classNames)
![](https://i-blog.csdnimg.cn/direct/978f52a34dc64f26b4ad2a02ae578f3d.png)
起送和结算显示控制(三元运算符)
购物车列表实现
![](https://i-blog.csdnimg.cn/direct/03cb87a3499842f29ce9220779fd28fa.png)
思路
![](https://i-blog.csdnimg.cn/direct/fe219dbf959745c2ada41da6f47cf4ca.png)
使用cartList渲染
![](https://i-blog.csdnimg.cn/direct/d77983c7c3f849d794032911783a8071.png)
把原本的cart干掉
![](https://i-blog.csdnimg.cn/direct/ca29136b28164976bf1f1e5a2cc1497f.png)
替换
![](https://i-blog.csdnimg.cn/direct/4e5782461ddb45d7b4131fadfb07236b.png)
![](https://i-blog.csdnimg.cn/direct/14c3fee36ac147b4a86aaaf1576d0c26.png)
添加visible显示
![](https://i-blog.csdnimg.cn/direct/a3be6dcb912548d5b4872539fd218037.png)
增减reducer,action提交
store编写
![](https://i-blog.csdnimg.cn/direct/f49e065b15ed4a8099f389424fb58911.png)
export导出
![](https://i-blog.csdnimg.cn/direct/00567e4d5d054c51ad137162a9bee3ae.png)
![](https://i-blog.csdnimg.cn/direct/3b32a855f0ae42de803bb35bb619ed0a.png)
熟悉Count组件
![](https://i-blog.csdnimg.cn/direct/84e582be4d5846ebaebd5d5e7a296bb1.png)
引入dispatcher
![](https://i-blog.csdnimg.cn/direct/a37793f9dc7d4d5a84214fa438ca05f6.png)
引入reducer
![](https://i-blog.csdnimg.cn/direct/f0696b3844d84f639f40c0aa2e43e4ea.png)
子传父触发回调
![](https://i-blog.csdnimg.cn/direct/37669bf0b8454d1a8448e8803bd7dd4b.png)
优化(不能是负数)
![](https://i-blog.csdnimg.cn/direct/093d900e6b54409b9171d33a4a7ab4e6.png)
store里修改(判断逻辑)
![](https://i-blog.csdnimg.cn/direct/6617f81d995b4615997a6013e5cf5871.png)
清空购物车
store编写
reducer
![](https://i-blog.csdnimg.cn/direct/d4babe08842f4c0ca5c66edb738f79e1.png)
export导出
![](https://i-blog.csdnimg.cn/direct/de423e7908544ea48376650665b7cca8.png)
cart组件引入reducer
然后导入dispatcher和reducer方法就可以了
控制购物车显示和隐藏
![](https://i-blog.csdnimg.cn/direct/76f4582f53df459aa55d25b26e5eb009.png)
思路(用useState控制,不用Redux)
![](https://i-blog.csdnimg.cn/direct/4f404aeab7f04e2fbbfff6aceda1c8fe.png)
![](https://i-blog.csdnimg.cn/direct/b8802281bea9443a81cd25b967d059fe.png)
![](https://i-blog.csdnimg.cn/direct/1f47537fdd1148829a9ce24396353761.png)
![](https://i-blog.csdnimg.cn/direct/3060449406ec4211853c4bbee95de4ee.png)
编写classNames
![](https://i-blog.csdnimg.cn/direct/b2af0ed1b05f43f3a54652db3b376295.png)
优化(购物车列表为空应该是不会有蒙层的)
![](https://i-blog.csdnimg.cn/direct/84b5a61af459442bb29cb161313a07a2.png)
编写onShow函数控制
![](https://i-blog.csdnimg.cn/direct/34e85b6c602f42a7a61ca1829c44696a.png)
修改之前的setVisible方法为onShow
![](https://i-blog.csdnimg.cn/direct/2a035fc756f34dd8a9bd615c88b11425.png)
总结:多组件共享才要放到Redux里面去,如果不用的话直接用useState就可以了。
26、react-router
前言提示
Vue中不需要export页面,而React就需要
![](https://i-blog.csdnimg.cn/direct/85759decab4648039678851f9e37ea12.png)
npx create-react-app react-router-pro
npm i react-router-dom
npm run start
![](https://i-blog.csdnimg.cn/direct/6169015028514f3eb5712259ecee8881.png)
实际的router配置
![](https://i-blog.csdnimg.cn/direct/61eddab9c68841e59c1123ed778f96f7.png)
创建Login和Article页面并export
![](https://i-blog.csdnimg.cn/direct/5ab43256508d4b4cb3631a4b18c52514.png)
创建router目录并import组件最后export
![](https://i-blog.csdnimg.cn/direct/81214c5bbbd047ddb40cbdb2cf5efc48.png)
index.js中注入router并且去配置即可
![](https://i-blog.csdnimg.cn/direct/0008195f3fdb4ad2877df035ad7ddc62.png)
路由导航
![](https://i-blog.csdnimg.cn/direct/660a7ee5dbfd401b82e6f1afb7117d1f.png)
声明式导航(Link)
![](https://i-blog.csdnimg.cn/direct/1fb70169f1794fd68d0ffbd3f95216b1.png)
编程式导航(useNavigate)
![](https://i-blog.csdnimg.cn/direct/4caac07c805c40a682b7b7fa63cf5bb8.png)
![](https://i-blog.csdnimg.cn/direct/74553d03dc2a4aa7a07e69a85db03bb9.png)
导航跳转传参
1、useSearchParams
![](https://i-blog.csdnimg.cn/direct/7fb98e062b144902af94b772f0178fd2.png)
在Article页接收参数![](https://i-blog.csdnimg.cn/direct/ea00844662e440bda5637360eacf295e.png)
2、useParams
![](https://i-blog.csdnimg.cn/direct/ada4f6cce7be480f80e4c5044c2ce599.png)
这个id是哪里来的呢?要到router实例去配置
编写样式
![](https://i-blog.csdnimg.cn/direct/2b07018f37fa46a2aa4704e84494db72.png)
到router位置给占位符(重中之重)
![](https://i-blog.csdnimg.cn/direct/e7e69bb0267a4066b20d23a161ef1d6e.png)
后面要接收多个参数的话同样的方式操作即可
![](https://i-blog.csdnimg.cn/direct/edc462a996ef47279493b8dfc92a1499.png)
![](https://i-blog.csdnimg.cn/direct/15fc1175d30b42a98c5d54cc47d8cc0a.png)
在Article页接收id
![](https://i-blog.csdnimg.cn/direct/d9e57e2d066c4ac5bf4d0cfa9f272475.png)
嵌套路由配置
Outlet
配置基本跟Vue没什么两样,多了个Outlet而已 ,作为二级路由出口
![](https://i-blog.csdnimg.cn/direct/c5d2ec91d3744a47842d11ecac67cb5d.png)
![](https://i-blog.csdnimg.cn/direct/40ea8d86a5d0459f8e5d214df667f1fc.png)
默认二级路由
![](https://i-blog.csdnimg.cn/direct/abc86f861f004f57be5e7698f53af087.png)
我们要的是一进入就有显示"我是面板",而不用专门去点击
404路由配置(path用星号"*"配置)
兜底组件
![](https://i-blog.csdnimg.cn/direct/c0431ee550c74e97a0f2b7ba321de253.png)
提高体验感
可以加一些按钮之类跳转到首页
两种路由模式
![](https://i-blog.csdnimg.cn/direct/82b490d65b49402da8946a3e2cd222b3.png)
换成hash模式的话直接替换API就可以了,切换页面的时候路径前面有#
![](https://i-blog.csdnimg.cn/direct/0fcda7193aeb4105a5d3a482ff378b0d.png)
![](https://i-blog.csdnimg.cn/direct/da507f2b961942ea8ed868685d05b341.png)
在实际开发中,后端支持的话就选history模式,不支持就选hash模式,其实没什么差别
记账本项目
功能演示
![](https://i-blog.csdnimg.cn/direct/768e0a7031ab4814aa7d11075b21dc23.png)
讲解:可以切换月份,可以切换年份,会展示每个月份的收支,可以输入"记一笔"
准备工作
移动端组件库antd-mobile
是阿里出品的适应React项目的组件库
![](https://i-blog.csdnimg.cn/direct/10c5828e0a9c4b008b80f68de431d012.png)
配置别名路径@
![](https://i-blog.csdnimg.cn/direct/ec3a3a67bc4743f6bb1597bdbe8e31b4.png)
配置步骤
![](https://i-blog.csdnimg.cn/direct/5e5a0e8c8d9848a6bc8b5ffaa9e5e5ed.png)
修改pages.json的scripts
![](https://i-blog.csdnimg.cn/direct/7fefeaab044d4150a2e77c6f8c43de3a.png)
![](https://i-blog.csdnimg.cn/direct/0a466721a4f6486f9c0917c591c9173d.png)
启动
npm run start
创建test.js测试
![](https://i-blog.csdnimg.cn/direct/e36bd2d05f644f7585819f4d78da9c7b.png)
index.js导入
![](https://i-blog.csdnimg.cn/direct/5b682f84f1ac477dabb9ed0b18eb2cec.png)
VsCode路径联想配置
数据Mock实现
json-sever实现数据mock
![](https://i-blog.csdnimg.cn/direct/5ea45daa7b194b0e8b6feba8d29b7bfe.png)
npm i -D json-sever
server目录下创建data.json文件放入数据
![](https://i-blog.csdnimg.cn/direct/ad7ca3834cab44fcbe42232b264cb60b.png)
添加启动命令
![](https://i-blog.csdnimg.cn/direct/170be7162ddf4444914acd8239b04bc9.png)
意思是添加一个以data.json为数据源,端口号为8888的服务器
启动
npm run serve
访问接口
![](https://i-blog.csdnimg.cn/direct/d5f3b269671048588eb8fdaf0f00b902.png)
配置路由
编写router和pages
![](https://i-blog.csdnimg.cn/direct/4d108e19b1f74d3fafb0110ffb2f8295.png)
index.js引入
配置二级路由
![](https://i-blog.csdnimg.cn/direct/59ce5922b0884394b65f12d1932e1136.png)
antD-mobile主题定制
![](https://i-blog.csdnimg.cn/direct/99fcc56a72da4bbfb73ad5d7a2560104.png)
编写css文件
![](https://i-blog.csdnimg.cn/direct/50ffb235bd494262bdcb2f6c7a9151cc.png)
注入到入口文件
![](https://i-blog.csdnimg.cn/direct/0c109e7a991f45049d187b8365a905c4.png)
到官方文档可以看见更多配置
![](https://i-blog.csdnimg.cn/direct/4e8abdedae3249b295ec1dede39b9a57.png)
Redux管理账目列表
思路
![](https://i-blog.csdnimg.cn/direct/16daa8bba93a450284819d89a9066a00.png)
![](https://i-blog.csdnimg.cn/direct/61b52c4333b44fcba528a2e2e8daaa14.png)
补充name
![](https://i-blog.csdnimg.cn/direct/89a01c51d26447669d94671d9ee2bc83.png)
![](https://i-blog.csdnimg.cn/direct/9d48710888bd4e40be041b8b7b99b468.png)
![](https://i-blog.csdnimg.cn/direct/3a81369ea74c4fd8a651d527b349e4be.png)
编写异步(!!!)
![](https://i-blog.csdnimg.cn/direct/dd79b568a0544729a96419946d1197ec.png)
记得导出异步
![](https://i-blog.csdnimg.cn/direct/0c947afb9bbe4a6cb7b97ec989672f1b.png)
测试即可
TabBar
![](https://i-blog.csdnimg.cn/direct/d3c28d75b8ff4e569a17026be9df22af.png)
静态布局实现
ant design mobile官网查找
![](https://i-blog.csdnimg.cn/direct/d0c4802ea3c544c1b97d4332e8b93da5.png)
这个去看老师代码就可以
导入代码和scss文件
npm i scss
配置跳转路由(onChange、useNavigate)
![](https://i-blog.csdnimg.cn/direct/31c2734284c44d43966a8e175a77a714.png)
统计功能
![](https://i-blog.csdnimg.cn/direct/066180f9742c43c8b728d18dcde0ce51.png)
需要实现的:可以切换不同月份的账单,小箭头有一个交互的效果,然后下面的三个部分都有统计
源代码去文档复制即可
点击切换搜索
![](https://i-blog.csdnimg.cn/direct/4631b51c63ea4c81abe3d3c7449f619a.png)
![](https://i-blog.csdnimg.cn/direct/7b96daa85f8c46dba7dd9f1bdb14d3a6.png)
换一下visible
![](https://i-blog.csdnimg.cn/direct/08c918e0732b4b808d5f8ee6311fd36e.png)
![](https://i-blog.csdnimg.cn/direct/6910accbab344b9fbc25cd3eb9910a01.png)
关闭弹窗(onCacel)
![](https://i-blog.csdnimg.cn/direct/b3b6c01d555d4bb28a8a36a1e873920c.png)
onConfirm
![](https://i-blog.csdnimg.cn/direct/d47bab10c2a848249015dcc7a14b942c.png)
蒙层(onClose)
![](https://i-blog.csdnimg.cn/direct/9484c5a1469c4375b0f4f81e670f0f65.png)
可以都换成一个函数然后绑定
![](https://i-blog.csdnimg.cn/direct/fda11bce4b5546d389639b43676da23b.png)
切换上下箭头
![](https://i-blog.csdnimg.cn/direct/393652c362584af2bdef5f1e7452a5fe.png)
点击确定切换时间显示
逻辑:点击确定的时候会回调一个时间,我们调用一下set方法就可以了
![](https://i-blog.csdnimg.cn/direct/207f8a0c318241a7a402a1a943ce207e.png)
嵌入CurrentDate
![](https://i-blog.csdnimg.cn/direct/18de0e0b87044c9cb743f2c0e819a02f.png)
这里会显示错误,加个字符串就可以
时间显示有点长,引入dayjs进行格式化
![](https://i-blog.csdnimg.cn/direct/8986be3d747e48e2b2a6a5c3e8459bc0.png)
![](https://i-blog.csdnimg.cn/direct/2239204db1234dc795a1ebc075874d16.png)
账单数据按月分组
![](https://i-blog.csdnimg.cn/direct/6189042768084c7f88a78e1d732cf470.png)
从Redux中拿到数据以及二次处理(useMemo)
![](https://i-blog.csdnimg.cn/direct/e31299be88024dd2a5402b1d13382df9.png)
按月分组(lodash)
npm i lodash
![](https://i-blog.csdnimg.cn/direct/1b1321999cc44db09b718c49dedc564f.png)
![](https://i-blog.csdnimg.cn/direct/33de9afc6294422c9fabf59bf42f75dd.png)
计算统计数据
![](https://i-blog.csdnimg.cn/direct/435253d358ec42999ed8251a2a29602a.png)
获取当前月
![](https://i-blog.csdnimg.cn/direct/2b6a1d17fc384a8dba079ed77d354f56.png)
定义monthList
![](https://i-blog.csdnimg.cn/direct/e6aff7064b9d4b1497165be97c3f5aef.png)
从useMemo取到数据
![](https://i-blog.csdnimg.cn/direct/2c0cd66fda6044d096aa79feec330d64.png)
编写新Memo
![](https://i-blog.csdnimg.cn/direct/a1ff123b533a4291bdc68cbaee003557.png)
渲染数据
![](https://i-blog.csdnimg.cn/direct/58dffef3d3d64200bd38769bbac426c7.png)
初始化计算
![](https://i-blog.csdnimg.cn/direct/c5dfb827663f4927be9c672d9512a170.png)
![](https://i-blog.csdnimg.cn/direct/1cd3d489e9694b79a8671859e4ba4789.png)
当日统计
![](https://i-blog.csdnimg.cn/direct/e048094c60e7484c914c0258ac14c5b7.png)
组件去复制模版然后export,导入到index.js就可以
子组件接收
![](https://i-blog.csdnimg.cn/direct/0fba0c7038c84730b1abca1793af45c2.png)
引入父组件的计算逻辑
![](https://i-blog.csdnimg.cn/direct/815e40cb18104e0d9d171d67a27db78e.png)
更换遍历数据
![](https://i-blog.csdnimg.cn/direct/fe90d397748e45adadce36fe025e579f.png)
单日账单列表显示![](https://i-blog.csdnimg.cn/direct/513db483c0074b32af395e3a9a0fb11c.png)
复制模版
![](https://i-blog.csdnimg.cn/direct/e754c53aea3f4cf685de11348294dad6.png)
复制数据
![](https://i-blog.csdnimg.cn/direct/fb20f264e13a4fa8928d99f111658c30.png)
底部的累加器中英文关系
![](https://i-blog.csdnimg.cn/direct/e968bf3add064300b095b4d1714d9e5a.png)
引入
![](https://i-blog.csdnimg.cn/direct/cd36a6ac41ec4ee0b35dc588a8db885a.png)
点击切换
![](https://i-blog.csdnimg.cn/direct/a06be13312af490daf32ea8d3772982b.png)
![](https://i-blog.csdnimg.cn/direct/4759db7f7a164a84a8a7062f3da0149e.png)
控制显示隐藏
![](https://i-blog.csdnimg.cn/direct/931e1eb7df784c4ba5af1ef492839c74.png)
![](https://i-blog.csdnimg.cn/direct/4cb2858150dc4cb185fe7a1f28c22bbc.png)
更换图标
![](https://i-blog.csdnimg.cn/direct/dd3bd325d6d14c82b505805a09363cae.png)
基地址不变,变图片就可以
准备静态代码,然后引入即可
![](https://i-blog.csdnimg.cn/direct/cbe6efacffde468e810d427885fb640d.png)
父传子
![](https://i-blog.csdnimg.cn/direct/faccf10a15264a4ca75f2810265ea9ce.png)
![](https://i-blog.csdnimg.cn/direct/def5a3a509c04b9d98c6d9d5f8dff4a0.png)
新增账单
![](https://i-blog.csdnimg.cn/direct/3e337773d839434e86e3543c338b4ff3.png)
还是一样去复制New代码
![](https://i-blog.csdnimg.cn/direct/d50158a8c3b14045858cb833bbb176b0.png)
![](https://i-blog.csdnimg.cn/direct/3191cb96ff5f499eb99253b61e31cf7b.png)
![](https://i-blog.csdnimg.cn/direct/d96729b338fd4be8bb8c4fcc32bef8a0.png)
设置激活状态
![](https://i-blog.csdnimg.cn/direct/6564bb52a11d4d8e9d50e11e97f671a0.png)
设置页面切换
![](https://i-blog.csdnimg.cn/direct/869ca554779a414e981aa408e4d30444.png)
新增表单实现
![](https://i-blog.csdnimg.cn/direct/4227e5d790f44575b323ab083ff3c061.png)
绑定value和onChange
绑定账单类型,useFor
![](https://i-blog.csdnimg.cn/direct/dee9120096f54c0b8cab19479dbd3b8a.png)
![](https://i-blog.csdnimg.cn/direct/dc5e0e1a493745ceb53dc48c999b2502.png)
编写Redux
![](https://i-blog.csdnimg.cn/direct/e2ae91baa9f04d608b12dc8c1f972a78.png)
![](https://i-blog.csdnimg.cn/direct/75a657b6db0e4c068ced790b6d7d75ff.png)
主文件引入
![](https://i-blog.csdnimg.cn/direct/8c789beff9e64dc59b99865765ede140.png)
![](https://i-blog.csdnimg.cn/direct/34fbc5212a4e4598aa63ed78d1ffe0d2.png)
![](https://i-blog.csdnimg.cn/direct/495f173c4c654b0a9d5b129a87d9ec89.png)
收尾优化
高亮
当选中种类后也有选择效果
![](https://i-blog.csdnimg.cn/direct/fab836ade9bf4b5eabd45c255bbdab5a.png)
![](https://i-blog.csdnimg.cn/direct/8e89bf026dcc436296110054f7fe95a1.png)
时间记账
![](https://i-blog.csdnimg.cn/direct/bde82906f0b3404dbb94793f95da6f93.png)
![](https://i-blog.csdnimg.cn/direct/87c71dd0d8cb4c0387dfd6f8fc484968.png)
设置visible
![](https://i-blog.csdnimg.cn/direct/7183884d31aa451282271d889bd7c946.png)
点击确定
![](https://i-blog.csdnimg.cn/direct/7400c96947454502828854f499295ce6.png)
存储时间
![](https://i-blog.csdnimg.cn/direct/b7866931c9224753a785e0c6fbb9757d.png)
修改完状态后关闭时间选择器
![](https://i-blog.csdnimg.cn/direct/faabb33b6eba404ea96c282bd0becab3.png)
修改时间
![](https://i-blog.csdnimg.cn/direct/a7a6a52f66884cd99bf35d755dcb5458.png)
![](https://i-blog.csdnimg.cn/direct/e3406e373d0d4f959525c3f2f3c2bb2e.png)