前言:以下内容基于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. Cisco IPC Emergency Responder Error

    Upon startup of the newer Cisco IP Communicator clients (especially on Windows Vista/7), sometimes y ...

  2. Nodejs express框架 浅析

    http://www.expressjs.com.cn/ 1. 中间件 ①挂载中间件的函数:app.use var http = require('http'); var express = requ ...

  3. Hoof, Paper, Scissors(USACO)

    题目大意: 一种游戏(类似于石头剪刀布):两个人分别给出一个字母,然后比较:H>S,S>P,P>H,我们已知对手的字母顺序,求在前n局中我们最多能赢多少次. 由于出字母的人非常懒,所 ...

  4. 跳石头(NOIP2015) (二分查找)

    原题传送门 好久没更了..昨天去学zkw线段树,被zxyer狠狠地D了一顿.. 来补坑.. 这是一道很奇特的题目. 根据题目可以看出这道题有二分题具有的性质.. 不懂二分性质的可以看我以前的博客 传送 ...

  5. MATLAB7 + sqlitejdbc-v056.jar 访问数据库

    以下代码出错: conn=database('data.db','','','org.sqlite.JDBC','jdbc:sqlite:C:/MATLAB7/work/del_man_voice_f ...

  6. 2.tornado请求与响应

    之前我们介绍了tornado的基础流程,但还遗留了一些问题.今天我们就来解决遗留问题并学习新的内容 settings,使用tornado.web.Application(handler, **sett ...

  7. 如何使用python查看视频的长度

    import subprocess import re def get_length(filename): result = subprocess.Popen(["ffprobe" ...

  8. WCF 小程序案例以及序列化的使用

    using System;using System.Collections.Generic;using System.Linq;using System.Runtime.Serialization;u ...

  9. AC日记——[SCOI2008] 着色方案 bzoj 1079

    1079 思路: dp: 我们如果dp方程为15维,每维记录颜色还有多少种: 不仅tle,mle,它还re: 所以,我们压缩一下dp方程: 方程有6维,第i维记录有多少种颜色还剩下i次: 最后还要记录 ...

  10. 牛客网 暑期ACM多校训练营(第二场)D.money-贪心 or 动态规划

    D.money 贪心,直接贴官方的题解吧. 题目大意 你要按照顺序依次经过n个商店,每到达一个商店你可以购买一件商品,也可以出售你手中的商品. 同一时刻你手上最多拿一件商品.在第i个商店购买和出售的代 ...