背景:十月十二日进入了新公司.负责PC端.使用技术:AntDesign,React,dva.分配的项目模块是财务回款.AntDesign中涉及到的组件有:
Button按钮 Icon图标 Text文本 Title标题 Grid栅格 Form表单 Pagination分页 Steps步骤条 Checkbox多选框 DatePicker日期选择框 Input输入框 InputNumber数字输入框 Radio单选框 Select选择器 Badge徽标数 List列表 Tag标签, Table表格 Drawer抽屉 Message全局提示 Result结果 Spin加载中 Search搜索 Divider分割线 Descriptions描述列表
历经一个月.如今已开发联调完毕.成功上线.今天恰好有时间,整理下本身遇到的难点和解决思路.git
由于是新的项目,因此项目小组长会给一个git地址,上面有一个空的antd的架子.直接从git上拉下来在这个空架子里开发就好.若是不会从git上拉取项目的能够看这里git命令
,由于一个项目有多个模块,这样你们每次都是在同一个环境下开发的.因此用一个git地址.每一个人每次写完本身的页面后就提交代码合并就行了.
这个是antd pro 的项目目录:
简单介绍下经常使用的文件夹:
config里面是路由
mock是模拟接口的
public里面放图片
页面在src下面写.
三层结构.services,models,pages.
services里面是链接后端接口的
models是把拿到的接口数据转换为使用的数据
pages里面是页面层,画页面,调接口,跳转页面等操做.
util里面是工具.
基本上经常使用的就是这些.上家公司是把全部的model都统一写在model层里,全部的services都写在services里.如今这家公司.我发现他们都是在一个文件夹里面.写本身的model和services.就像这样:
.js文件里面就是写页面和逻辑的地方,页头引入组件,class上面引入model层,引入Form,里面写你的state,还有方法,render里面写return.后端
.less里面是页面样式,就像这样,直接写.
model层里面是接口返回的值.
关注的点有:
namespace.就是你定义的你的model层的名字
effcts里面就是你获取的接口的值.能够在这里处理接口调成功后的逻辑.callback.
reducers里面就是你的异步方法返回值.
srvice里面是链接后端接口的.
基本上开发一个页面,文件夹下就是这四个文件.
在这里,我遇到了第一个问题,就是页面较为复杂,好比有步骤条的页面,代码写着写着就1000行了.整个页面代码不少,不利于管理.后面请教了同事.学会了分割页面,把一个步骤条做为一个子组件,放在一个父组件里面.这时候,目录就变成了这样:
当父组件页面须要展现子组件的时候,把子组件引用过来.就像这样:antd
import StepsOne from './components/stepsOne'; import StepsTwo from './components/stepsTwo'; import StepsThree from './components/stepsThree'; import StepsFour from './components/stepsFour';
使用的时候:less
<Steps current={current} className={styles['steps_title']}> {steps.map(item => ( <Step key={item.title} title={item.title} /> ))} </Steps> <div className="steps-content"> {current == 0 && ( <StepsOne getOneListData={listData => this.getOneListData(listData)} val={this.state.val} /> )} {current == 1 && ( <StepsTwo datalist={datalist} getTwoListData={(listDataTwo, data1) => this.getTwoListData(listDataTwo, data1)} /> )} {current == 2 && ( <StepsThree datalistTwo={datalistTwo} onRef={ref => this.stepThreeRef(ref)} aClaimAmounts={aClaimAmounts} getThreeNote={note => this.getThreeNote(note)} /> )} {current == 3 && <StepsFour aClaimAmounts={aClaimAmounts} datalistTwo={datalistTwo} />} {current == 4 && ( <Result status="success" title="提交成功" subTitle="提交日期 2019-10-15" style={{ background: 'white', height: '100%', bottom: '3%' }} extra={[ <Button key="1" type="primary" onClick={() => this.newApplication()}> 填写新的申请 </Button>, <Button key="2" onClick={() => this.goDetails()}> 查看详情 </Button>, ]} /> )}
可能我写的比较多.看起来不是很顺.大概这样理解:
把子组件引入后,在须要使用的地方,直接用标签<StepsOne /> 这样使用就能够获得子组件的内容了.至于个人datalist={datalist} 这个意义是向子组件传值.{datalist}这里面的datalist是我把父组件里的state里的datalist解析出来的值.异步
getTwoListData={(listDataTwo, data1) => this.getTwoListData(listDataTwo, data1)}
这个意义是子组件向父组件传值.ide
onRef={ref => this.stepThreeRef(ref)}
这个意义是父组件能够拿到子组件内全部的值,包括state里面的.
在使用onRef方法的时候,须要先在子组件内的componentDidMount方法里面定义:this.props.onRef(this);而后在父组件内才能够拿到.父组件拿值:
我是在父组件的state里面定义了一个变量,用来存储第三个步骤条全部的值.工具
stepThreeRef = ref => { this.setState({ threeRef: ref }); };
这个很绕很绕,静态页面我一个礼拜就写完了.联调接口的时候,这几个步骤条加上传值取值赋值花了我联调一半的时间,哈哈哈哈.女生嘛,逻辑差了那么一点点~ 理解起来就会有难度~写的就慢了~我也是查了N个百度又问了好几回同事才解决了这些问题.之后多写写应该就顺了就快了.
其余的组件都比较简单,引入后直接使用就行了.可是步骤条和抽屉是有逻辑在里面的,这两个组件以前都没有用过.因此这个项目写起来仍是花了点时间的.
好比此次我写项目使用的步骤条逻辑(记录一下,哈哈哈哈):
第一个页面有一个单选列表.使用的组件有Table表格,Tag标签,Search搜索,Radio单选框
点击下一步去第二个页面的时候,须要把单选后的列表内容所有传过去.而且这个单选是必选.若是没有选,就要用Message全局提示弹框.
第二个页面,分为两部分,展现公司名称和回款单还有发票.使用的组件有:
点击回款详情是打开一个抽屉,里面有回款单信息:
点击上一步是返回第一个步骤条页面,而且第一个页面以前选中的数据要保持选中的状态.点击取消也是回到第一个步骤条页面,不过选中的状态要取消.点击下一步去第三个步骤条页面.须要把第二个页面的单选回款单和多选发票带过去.这两个必须判断两个都必选一个,不然弹框,页面也停留在当前页.就像这样:
两个都选中后点击下一步就能够进入第三个页面了.
第三个页面展现的就是第二个页面传过来的回款单和发票,而且每一个发票下面有不少个行项目,截图的是一个,后续会有不少.因此这里要遍历展现发票列表.且每一个行项目均可以输入金额匹配.右下方的本次匹配金额动态增长或减小.好了,在这里我遇到了个人第二个问题:页面下方的本次匹配金额如何动态相加减输入框的金额.输入框的金额是有方法能够拿到的.e.target.value.相信通常你们都知道.可是页面上可能有N个输入框.这个是不肯定的.后面想到,这个输入框我是放在Form下面的..可能我写的复杂了.可是那时候就是这样想的.后面同事就给我推荐了Form表单的一个方法,叫这个!!!this.props.form.getFieldsValue();贼好用.一次性给我把页面的输入框内容所有获取到了.并且我还踩坑了,开始绑定的是onChange方法,后面发现有点bug,由于是onChange方法是输入框值改变的时候才触发的,若是用户点击输入框后没有作改变,可是你总值又相加减了,就会有问题.后面用的是onBlur方法.失焦的时候触发.这样的就能够避免用户点击输入框后不作操做也不会影响最终值了.由于我是在方法内把全部的值相加了~ 好吧~ 我以为稍微有点点蠢,可是没想到好方法.就用的这个了.最终结果就是本次匹配金额随着输入框的值动态相加减.仍是实现了,哈哈哈哈哈.点击上一步回到第二个页面,第二个页面要选中当时来第三个页面的时候选中的值.第三个页面用的组件也介绍下:
判断逻辑也有不少,好比输入框值不能大于未匹配,本次匹配总金额不能大于未匹配金额.不然弹框,停留
所有都符合条件后,点击下一步成功来到第四个页面.
这个页面和第三个页面不同的点就是输入框变成了展现,备注也变成了只读.点击上一步回到第三个页面,第三个页面输入框要显示以前输入的数字,备注也是同样.
第四个页面点击提交来到第五个页面.这里点击提交的时候是不用作逻辑判断的,可是要发接口.把全部的参数传给后端.若是接口返回错误了,页面也会停留.
这里介绍了我模块中最复杂的一个页面.
其余的四个页面就是一些展现数据,搜索,抽屉详情,跳转抽屉等等没啥难度了.
说下跳转页面我用方法:this
goDetails = () => { const {id} = this.state router.push({ pathname: '/receivableManagement/receivableDetails', query: { id, }, }); };
pathname就是页面路径,query里面是传参.把参数带到跳转后的页面去.取参数就是用query取:spa
// 获取回款单内容 getListCompletedMatch = () => { const { location: { query }, } = this.props; this.setState({ loading: true }); this.props.dispatch({ type: 'receivableDetailsModel/getListCompletedMatch', data: { paymentId: query.id }, callback:data =>{ this.setState({ loading: false }); } }); };
还有一些小坑坑就不一一诉说了.在这个模块中收获最多的就是动态获得输入框相加减后的值,还有步骤条父组件子组件传值.以及抽屉,多个抽屉跳转.好用的方法有:
给金额后保留两位小数.Number(amount).toFixed(2);
这个toFixed()方法必定要是Number类型的值,括号里就是保留的小数位.
输入框失焦的时候触发的onBlur方法.能够取到最后一个值.
获取Form表单下的所有输入框值:this.props.form.getFieldsValue()设计
放几张写好的页面~