前言:以下内容基于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. 深入解析Linux内核I/O剖析(open,write实现)

    Linux内核将一切视为文件,那么Linux的文件是什么呢?其既可以是事实上的真正的物理文件,也可以是设备.管道,甚至还可以是一块内存.狭义的文件是指文件系统中的物理文件,而广义的文件则可以是Linu ...

  2. Golang/Go语言/Go IDE/Go windows环境搭建/Go自动提示编译器/GoSublime

    Go是Google开发的一种编译型,并发型,并具有垃圾回收功能的编程语言. 罗伯特·格瑞史莫(Robert Griesemer),罗勃·派克(Rob Pike)及肯·汤普逊于2007年9月开始设计Go ...

  3. js正则常用的一些东西

    mdn的正则文档 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions js正则表达式的分 ...

  4. 经常用的Jquery图片轮转

    1.HTML结构 <div class="main_view">                 <div class="window"> ...

  5. DotNetCore 笔记

    最近公司框架升级到DotNetCore了,但是在用post请求的时候,发现页面的post data后台并没有接收到数据,经过调查发现,netcore用法和之前的MVC5不一样,想要接收post里的da ...

  6. Tomcat配置连接池

    Tomcat配置DBCP连接池 配置tomcat服务器的时候,使用到jndi;通过Context配置文件实现配置池对象,通过new initialConext()对象的lookup()获取到数据池对象 ...

  7. luogu P1468 派对灯 Party Lamps

    题目描述 在IOI98的节日宴会上,我们有N(10<=N<=100)盏彩色灯,他们分别从1到N被标上号码. 这些灯都连接到四个按钮: 按钮1:当按下此按钮,将改变所有的灯:本来亮着的灯就熄 ...

  8. highcharts 图例详解

    highcharts 图例 tooltip: {                                           },                      legend: { ...

  9. [CP1804]最短路

    题目大意: 一个$n(n\le10^5)$个点的图,给定一个常数$c$,每对点$i,j$之间有权值为$(i\oplus j)\times c$的边.另有$m(m\le5\times10^5)$条指定权 ...

  10. kong后台接口

    在nginx-kong.lua中,require('lapis').serve('kong.api'),先require文件/usr/local/share/lua/5.1/lapis/init.lu ...