前言:以下内容基于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后台管理系统开发手记:项目工程化开发的更多相关文章

  1. OpenDaylight开发hello-world项目之开发环境搭建

    OpenDaylight开发hello-world项目之开发环境搭建 OpenDaylight开发hello-world项目之开发工具安装 OpenDaylight开发hello-world项目之代码 ...

  2. OpenDaylight开发hello-world项目之开发工具安装

    OpenDaylight开发hello-world项目之开发环境搭建 OpenDaylight开发hello-world项目之开发工具安装 OpenDaylight开发hello-world项目之代码 ...

  3. 【共享单车】—— React后台管理系统开发手记:主页面架构设计

    前言:以下内容基于React全家桶+AntD实战课程的学习实践过程记录.最终成果github地址:https://github.com/66Web/react-antd-manager,欢迎star. ...

  4. 【共享单车】—— React后台管理系统开发手记:AntD Table基础表格

    前言:以下内容基于React全家桶+AntD实战课程的学习实践过程记录.最终成果github地址:https://github.com/66Web/react-antd-manager,欢迎star. ...

  5. 《React后台管理系统实战 :一》:目录结构、引入antd、引入路由、写login页面、使用antd的form登录组件、form前台验证、高阶函数/组件

    实战 上接,笔记:https://blog.csdn.net/u010132177/article/details/104150177 https://gitee.com/pasaulis/react ...

  6. react后台管理系统路由方案及react-router原理解析

        最近做了一个后台管理系统主体框架是基于React进行开发的,因此系统的路由管理,选用了react-router(4.3.1)插件进行路由页面的管理配置. 实现原理剖析 1.hash的方式   ...

  7. 《React后台管理系统实战 零》:基础笔记

    day01 1. 项目开发准备 1). 描述项目 2). 技术选型 3). API接口/接口文档/测试接口 2. 启动项目开发 1). 使用react脚手架创建项目 2). 开发环境运行: npm s ...

  8. 【共享单车】—— React后台管理系统开发手记:Redux集成开发

    前言:以下内容基于React全家桶+AntD实战课程的学习实践过程记录.最终成果github地址:https://github.com/66Web/react-antd-manager,欢迎star. ...

  9. 【共享单车】—— React后台管理系统开发手记:城市管理和订单管理

    前言:以下内容基于React全家桶+AntD实战课程的学习实践过程记录.最终成果github地址:https://github.com/66Web/react-antd-manager,欢迎star. ...

随机推荐

  1. centos 7 服务器网卡做bond

    前期环境准备 [root@ /root] alibaba cloud#cat /etc/redhat-releaseCentOS Linux release 7.4.1708 (Core)[root@ ...

  2. UVa10891 Game of Sum

    给定n个数字,A和B可以从这串数字的两端任意选数字,一次只能从一端选取.两人都采用最优策略,A先手,问A和B各自得到数字的和的差值最大为多少? 区间DP F[i][j]表示区间i~j内A能得到的最大数 ...

  3. GitHub上README写法暨markdown语法解读

    原文: GitHub上README写法暨markdown语法解读 自从开始玩GitHub以来,就 越来越 感觉它有爱.最近对它的 README.md 文件颇为感兴趣.便写下这贴,帮助更多的还不会编写R ...

  4. 花匠(NOIP2013)(神奇纯模拟)

    原题传送门 这是道很奇怪的题目,真不知道为什么要放到T2. 也许是T1太水了 首先先看题, 题目要求一个数列中下标为偶数的点比临近的下表为奇数的点更大或更小 其实就是说在原数组中找到一个最长的波动数列 ...

  5. linux反汇编

    使用objdump参数可以: -a, --archive-headers    显示压缩头信息   -f, --file-headers       显示目录头总览   -p, --private-h ...

  6. 从串口驱动的移植看linux2.6内核中的驱动模型 platform device & platform driver【转】

    转自:http://blog.csdn.net/bonnshore/article/details/7979705 写在前面的话: 博主新开了个人站点:你也可以在这里看到这篇文章,点击打开链接 本文是 ...

  7. protobuf 中的嵌套消息的使用 主要对set_allocated_和mutable_的使用

    protobuf的简单的使用,不过还留下了一个问题,那就是之前主要介绍的都是对简单数据的赋值,简单数据直接采用set_xx()即可,但是如果不是简单变量而是自定义的复合类型变量,就没有简单的set函数 ...

  8. MySql实现分页查询的SQL,mysql实现分页查询的sql语句(转)

    http://blog.csdn.net/sxdtzhaoxinguo/article/details/51481430 摘要:MySQL数据库实现分页查询的SQL语句写法! 一:分页需求: 客户端通 ...

  9. vue.js基本使用

    #原创,转载请留言联系 什么是vue.js Vue.js(读音 /vjuː/, 类似于 view) 是一套构建用户界面的渐进式框架. Vue 只关注视图层, 采用自底向上增量开发的设计. Vue 的目 ...

  10. Android 中带有进度条效果的按钮(Button)

    安卓中带有进度条效果的按钮,如下图: 1.布局文件如下activity_main.xml <RelativeLayout xmlns:android="http://schemas.a ...