【共享单车】—— React后台管理系统开发手记:项目工程化开发
前言:以下内容基于React全家桶+AntD实战课程的学习实践过程记录。最终成果github地址:https://github.com/66Web/react-antd-manager,欢迎star。
一、项目工程化概念

二、BaseForm的封装
城市管理中FilterForm子组件:

订单管理中FilterForm子组件:

员工管理中FilterForm子组件:

【项目工程化】:表单封装
- components->BaseForm->index.js
- 关键:抽象出formList,根据formList中的item.type判断要渲染的AnTD表单类型
const formList = this.props.formList;
- 实现表单数据的双向绑定:getFieldDecorator
const {getFieldDecorator } = this.props.form; <FormItem label={label} key={field}>
{
getFieldDecorator([field])(
<Input type="text" style={{width: width}} placeholder={placeholder}/>
)
}
</FormItem> - 获取组件中全部表单控件的内容:getFieldsValue()
handleFilterSubmit = () => {
let fieldsValue = this.props.form.getFieldsValue();
this.props.filterSubmit(fieldsValue);
} //order->index.js中
<BaseForm formList={this.formList} filterSubmit={this.handleFilter}/> handleFilter = (params) => {
this.params = params;
this.requestList();
} order->index.js中:按照AntD 的getFieldDecorator.option规则定义formList数据
formList = [
{
type: 'SELECT',
label: '城市',
field: 'city_id',
placeholder: '全部',
initialValue: '1',
width: 80,
list: [
{id: '0', name: '全部'},
{id: '1', name: '北京'},
{id: '2', name: '天津'},
{id: '3', name: '上海'}
]
},
{
type: '时间查询'
},
{
type: 'SELECT',
label: '订单状态',
field: 'order_status',
placeholder: '全部',
initialValue: '1',
width: 80,
list: [
{id: '0', name: '全部'},
{id: '1', name: '进行中'},
{id: '2', name: '结束行程'}
]
}
]BaseForm组件代码:
import React from 'react'
import { Input, Select, Form, Button, Checkbox, DatePicker} from 'antd'
import Utils from '../../utils/utils'
const FormItem = Form.Item; class FilterForm extends React.Component{ handleFilterSubmit = () => {
let fieldsValue = this.props.form.getFieldsValue();
this.props.filterSubmit(fieldsValue);
} reset = () => {
this.props.form.resetFields();
} initFormList = () => {
const {getFieldDecorator } = this.props.form;
const formList = this.props.formList;
const formItemList = [];
if(formList && formList.length>0){
formList.forEach((item, i) => {
let label = item.label;
let field = item.field;
let initialValue = item.initialValue || '';
let placeholder = item.placeholder;
let width = item.width;
if(item.type == '时间查询'){
const begin_time = <FormItem label="订单时间" key={field}>
{
getFieldDecorator('begin_time')(
<DatePicker showTime={true} placeholder={placeholder} format="YYYY-MM-DD HH:mm:ss"/>
)
}
</FormItem>;
formItemList.push(begin_time);
//~后省略冒号:label="~" colon={false}
const end_time = <FormItem key={field}>
{
getFieldDecorator('end_time')(
<DatePicker showTime={true} placeholder={placeholder} format="YYYY-MM-DD HH:mm:ss"/>
)
}
</FormItem>;
formItemList.push(end_time);
}else if(item.type == 'INPUT'){
const INPUT = <FormItem label={label} key={field}>
{
getFieldDecorator([field])(
<Input type="text" style={{width: width}} placeholder={placeholder}/>
)
}
</FormItem>;
formItemList.push(INPUT);
}else if(item.type == 'SELECT'){
const SELECT = <FormItem label={label} key={field}>
{
getFieldDecorator([field],{
initialValue: initialValue
})(
<Select
style={{width: width}}
placeholder={[placeholder]}
>
{Utils.getOptionList(item.list)}
</Select>
)
}
</FormItem>;
formItemList.push(SELECT);
}else if(item.type == 'CHECKBOX'){
const CHECKBOX = <FormItem label={label} key={field}>
{
getFieldDecorator([field],{
valuePropName: 'checked',
initialValue: initialValue //true | false
})(
<Checkbox>
{label}
</Checkbox>
)
}
</FormItem>;
formItemList.push(CHECKBOX);
}else if(item.type == 'DATE'){
const DATEPICKER = <FormItem label={label} key={field}>
{
getFieldDecorator([field])(
<DatePicker showTime={true} placeholder={placeholder} format="YYYY-MM-DD HH:mm:ss"/>
)
}
</FormItem>;
formItemList.push(DATEPICKER);
}
})
}
return formItemList;
} render(){
return (
<Form layout="inline">
{this.initFormList()}
<FormItem>
<Button type="primary" style={{margin:'0 10px'}} onClick={this.handleFilterSubmit}>查询</Button>
<Button onClick={this.reset}>重置</Button>
</FormItem>
</Form>
)
}
}
export default Form.create({})(FilterForm)
三、列表数据请求封装
每个管理模块几乎都有一个requestList()调用axios.ajax请求Easy Mock接口中的数据。
依据【项目工程化】思想,封装这部分代码,简化开发过程。
- src->axios->index.js中:定义requestList方法,接收_this、url、params、isMock参数
static requestList(_this, url, params, isMock){
var data = {
params: params,
isMock //使用Mock数据
}
this.ajax({
url,
data
}).then((data) => {
if(data && data.list){
let list = data.list.item_list.map((item, index) => {
item.key = index;
return item;
});
_this.setState({
list,
selectedRowKeys: [],//重置
pagination:Utils.pagination(data,(current)=>{
_this.params.page = current;
_this.requestList();
})
})
}
})
} order->index.js中:requestList()中直接调用axios.requestList()即可获取接口数据
requestList = () => {
axios.requestList(this, '/order/list', this.params, true)
}
四、ETable表格封装

原城市管理、订单管理:数据列表实现都需要以下内容
<div className="content-wrap">
<Table
bordered
columns={columns}
dataSource={this.state.list}
pagination={this.state.pagination}
rowSelection= {rowSelection}
onRow={(record, index) => {
return {
onClick: () => {
this.onRowClick(record, index);
}
}
}}
/>
</div>
单选列表项:定义selectedRowKeys和rowSelection、监听onRow事件
const selectedRowKeys = this.state.selectedRowKeys;
const rowSelection = {
type: 'radio',
selectedRowKeys
}
onRowClick = (record, index) => {
let selectKey = [index];
this.setState({
selectedRowKeys: selectKey,
selectedItem: record
})
}
【项目工程化】:封装可复用代码,扩展复选列表项功能
- utils->uitils.js:添加ETable行点击通用函数,判断选择框变更传入的参数是否有selectedIds,设置不同的state内容
/**
* ETable 行点击通用函数
* @param {*选中行的索引} selectedRowKeys
* @param {*选中行对象} selectedItem
*/
updateSelectedItem(selectedRowKeys, selectedRows, selectedIds) {
if (selectedIds) {
this.setState({
selectedRowKeys,
selectedIds: selectedIds,
selectedItem: selectedRows
})
} else {
this.setState({
selectedRowKeys,
selectedItem: selectedRows
})
}
} components->ETable->index.js:传入的this.props中若有selectedIds,设置checkbox渲染数据,否则,设置radio
import React from 'react'
import Utils from '../../utils/utils'
import {Table} from 'antd'
import "./index.less"
export default class ETable extends React.Component { state = {}
//处理行点击事件
onRowClick = (record, index) => {
let rowSelection = this.props.rowSelection;
if(rowSelection == 'checkbox'){
let selectedRowKeys = this.props.selectedRowKeys;
let selectedIds = this.props.selectedIds;
let selectedItem = this.props.selectedItem || [];
if (selectedIds) {
const i = selectedIds.indexOf(record.id);
if (i == -1) {//避免重复添加
selectedIds.push(record.id)
selectedRowKeys.push(index);
selectedItem.push(record);
}else{
selectedIds.splice(i,1);
selectedRowKeys.splice(i,1);
selectedItem.splice(i,1);
}
} else {
selectedIds = [record.id];
selectedRowKeys = [index]
selectedItem = [record];
}
this.props.updateSelectedItem(selectedRowKeys,selectedItem || {},selectedIds);
}else{
let selectKey = [index];
const selectedRowKeys = this.props.selectedRowKeys;
if (selectedRowKeys && selectedRowKeys[0] == index){
return;
}
this.props.updateSelectedItem(selectKey,record || {});
}
}; // 选择框变更
onSelectChange = (selectedRowKeys, selectedRows) => {
let rowSelection = this.props.rowSelection;
const selectedIds = [];
if(rowSelection == 'checkbox'){
selectedRows.map((item)=>{
selectedIds.push(item.id);
});
this.setState({
selectedRowKeys,
selectedIds:selectedIds,
selectedItem: selectedRows[0]
});
}
this.props.updateSelectedItem(selectedRowKeys,selectedRows[0],selectedIds);
}; onSelectAll = (selected, selectedRows, changeRows) => {
let selectedIds = [];
let selectKey = [];
selectedRows.forEach((item,i)=> {
selectedIds.push(item.id);
selectKey.push(i);
});
this.props.updateSelectedItem(selectKey,selectedRows[0] || {},selectedIds);
} getOptions = () => {
let p = this.props;
const name_list = {
"订单编号":170,
"车辆编号":80,
"手机号码":96,
"用户姓名":70,
"密码":70,
"运维区域":300,
"车型":42,
"故障编号":76,
"代理商编码":97,
"角色ID":64
};
if (p.columns && p.columns.length > 0) {
p.columns.forEach((item)=> {
//开始/结束 时间
if(!item.title){
return
}
if(!item.width){
if(item.title.indexOf("时间") > -1 && item.title.indexOf("持续时间") < 0){
item.width = 132
}else if(item.title.indexOf("图片") > -1){
item.width = 86
}else if(item.title.indexOf("权限") > -1 || item.title.indexOf("负责城市") > -1){
item.width = '40%';
item.className = "text-left";
}else{
if(name_list[item.title]){
item.width = name_list[item.title];
}
}
}
item.bordered = true;
});
}
const { selectedRowKeys } = this.props;
const rowSelection = {
type: 'radio',
selectedRowKeys,
onChange: this.onSelectChange,
onSelect:(record, selected, selectedRows)=>{
console.log('...')
},
onSelectAll:this.onSelectAll
};
let row_selection = this.props.rowSelection;
// 当属性未false或者null时,说明没有单选或者复选列
if(row_selection===false || row_selection === null){
row_selection = false;
}else if(row_selection == 'checkbox'){
//设置类型未复选框
rowSelection.type = 'checkbox';
}else{
//默认未单选
row_selection = 'radio';
}
return <Table
className="card-wrap page-table"
bordered
{...this.props}
rowSelection={row_selection?rowSelection:null}
onRow={(record,index) => ({
onClick: ()=>{
if(!row_selection){
return;
}
this.onRowClick(record,index)
}
})}
/>
};
render = () => {
return (
<div>
{this.getOptions()}
</div>
)
}
}order->index.js中:应用Eable组件实现
import ETable from './../../components/ETable' <div className="content-wrap">
<ETable
columns={columns}
updateSelectedItem={Utils.updateSelectedItem.bind(this)}
selectedRowKeys={this.state.selectedRowKeys}
//selectedIds={this.state.selectedIds}
selectedItem={this.state.selectedItem}
dataSource={this.state.list}
pagination={this.state.pagination}
/>
</div>
注:项目来自慕课网
【共享单车】—— React后台管理系统开发手记:项目工程化开发的更多相关文章
- OpenDaylight开发hello-world项目之开发环境搭建
OpenDaylight开发hello-world项目之开发环境搭建 OpenDaylight开发hello-world项目之开发工具安装 OpenDaylight开发hello-world项目之代码 ...
- OpenDaylight开发hello-world项目之开发工具安装
OpenDaylight开发hello-world项目之开发环境搭建 OpenDaylight开发hello-world项目之开发工具安装 OpenDaylight开发hello-world项目之代码 ...
- 【共享单车】—— React后台管理系统开发手记:主页面架构设计
前言:以下内容基于React全家桶+AntD实战课程的学习实践过程记录.最终成果github地址:https://github.com/66Web/react-antd-manager,欢迎star. ...
- 【共享单车】—— React后台管理系统开发手记:AntD Table基础表格
前言:以下内容基于React全家桶+AntD实战课程的学习实践过程记录.最终成果github地址:https://github.com/66Web/react-antd-manager,欢迎star. ...
- 《React后台管理系统实战 :一》:目录结构、引入antd、引入路由、写login页面、使用antd的form登录组件、form前台验证、高阶函数/组件
实战 上接,笔记:https://blog.csdn.net/u010132177/article/details/104150177 https://gitee.com/pasaulis/react ...
- react后台管理系统路由方案及react-router原理解析
最近做了一个后台管理系统主体框架是基于React进行开发的,因此系统的路由管理,选用了react-router(4.3.1)插件进行路由页面的管理配置. 实现原理剖析 1.hash的方式 ...
- 《React后台管理系统实战 零》:基础笔记
day01 1. 项目开发准备 1). 描述项目 2). 技术选型 3). API接口/接口文档/测试接口 2. 启动项目开发 1). 使用react脚手架创建项目 2). 开发环境运行: npm s ...
- 【共享单车】—— React后台管理系统开发手记:Redux集成开发
前言:以下内容基于React全家桶+AntD实战课程的学习实践过程记录.最终成果github地址:https://github.com/66Web/react-antd-manager,欢迎star. ...
- 【共享单车】—— React后台管理系统开发手记:城市管理和订单管理
前言:以下内容基于React全家桶+AntD实战课程的学习实践过程记录.最终成果github地址:https://github.com/66Web/react-antd-manager,欢迎star. ...
随机推荐
- Cisco IPC Emergency Responder Error
Upon startup of the newer Cisco IP Communicator clients (especially on Windows Vista/7), sometimes y ...
- Nodejs express框架 浅析
http://www.expressjs.com.cn/ 1. 中间件 ①挂载中间件的函数:app.use var http = require('http'); var express = requ ...
- Hoof, Paper, Scissors(USACO)
题目大意: 一种游戏(类似于石头剪刀布):两个人分别给出一个字母,然后比较:H>S,S>P,P>H,我们已知对手的字母顺序,求在前n局中我们最多能赢多少次. 由于出字母的人非常懒,所 ...
- 跳石头(NOIP2015) (二分查找)
原题传送门 好久没更了..昨天去学zkw线段树,被zxyer狠狠地D了一顿.. 来补坑.. 这是一道很奇特的题目. 根据题目可以看出这道题有二分题具有的性质.. 不懂二分性质的可以看我以前的博客 传送 ...
- MATLAB7 + sqlitejdbc-v056.jar 访问数据库
以下代码出错: conn=database('data.db','','','org.sqlite.JDBC','jdbc:sqlite:C:/MATLAB7/work/del_man_voice_f ...
- 2.tornado请求与响应
之前我们介绍了tornado的基础流程,但还遗留了一些问题.今天我们就来解决遗留问题并学习新的内容 settings,使用tornado.web.Application(handler, **sett ...
- 如何使用python查看视频的长度
import subprocess import re def get_length(filename): result = subprocess.Popen(["ffprobe" ...
- WCF 小程序案例以及序列化的使用
using System;using System.Collections.Generic;using System.Linq;using System.Runtime.Serialization;u ...
- AC日记——[SCOI2008] 着色方案 bzoj 1079
1079 思路: dp: 我们如果dp方程为15维,每维记录颜色还有多少种: 不仅tle,mle,它还re: 所以,我们压缩一下dp方程: 方程有6维,第i维记录有多少种颜色还剩下i次: 最后还要记录 ...
- 牛客网 暑期ACM多校训练营(第二场)D.money-贪心 or 动态规划
D.money 贪心,直接贴官方的题解吧. 题目大意 你要按照顺序依次经过n个商店,每到达一个商店你可以购买一件商品,也可以出售你手中的商品. 同一时刻你手上最多拿一件商品.在第i个商店购买和出售的代 ...