美文网首页技术码头
Ant Design Pro开发后台管理系统(Search)

Ant Design Pro开发后台管理系统(Search)

作者: 石菖蒲_xl | 来源:发表于2018-09-10 16:18 被阅读658次

    Search 搜索,提供一般列表页搜索,本文简单讲述一下设计思想。

    先看一下效果图

    组件只封装了 RangePicker、Input、Select三个搜索条件,可以继续扩展


    图1.我们要做什么

    为什么要封装Search组件?

    如图1列表页带搜索,运用场景很多,而且搜索条件有多有少,搜索类型也多有不同,产品还时不时的加或者删几个搜索条件......如果不封装的话我们每次使用都要引入大量antd组件代码,写一大堆Form,完全不不了一行组件,三两个参数简洁,美观。

    封装后的使用 (文章最后附上组件源码)
    const items = [{
      type: 'Input',
      label: 'ID查询',
      required: false,
      placeholder: '请输入id',
      parameter: 'id',
    }, {
      type: 'Select',
      label: '科目查询',
      required: false,
      placeholder: '请选择',
      parameter: 'subject',
      options: []
    }];
    <Search items={items} loading={loading} onSubmit={()=>{}} onReset={()=>{}}/>
    

    如此便生成图1的搜索组件,一次封装,N次受益,我们再也不需要写那些antd 的Form了,我们只需要看产品要求的搜索条件都是什么,去配置items(array)就可以了,具体参数下文会详细解说,然后再把搜索方法和重置方法的业务逻辑加上,整个搜索就完成了。

    Search组件的设计思路 “用对象生成UI”

    我们把Search整体看做一个大的容器,其中包含了“一定一不定”,操作方法一定(提交、重置),输入条件不一定,我所说的一定不一定指的是UI显示上。

    “一定”:所有的搜索基本上都需要“提交”、“重置”两个按钮。
    “提交”就是把输入的搜索信息提交到后台获取到列表数据,但是每个页面的搜索接口不一样,数据处理或许也有区别,所以我们把提交方法抛出来,用的时候把方法传入就可以。
    “重置”就是还原数据,重置搜索条件,清空搜索框,显示默认列表数据

    “一不定”:输入条件不一定,条件个数不一定,不过输入条件一般就是输入名称搜索、或者类型搜索(下拉框)、或者时间搜索

    需要提取的公共部分

    1、生成ui的数组
    2、提交、重置方法
    我们着重讲一下对象生成UI的概念
    首先我们把每一个搜索条件看成一个“框”
    “框”之间的差别:
    类型不一样Input、Select...,
    提交参数名字不一样,
    搜索框名字不一样
    ...
    (我们默认一行显示三个组件,缺憾,待完善)

    /**
     *   items [{       | array     | 数组包含元素对象
     *     type         | string    | 类型 判断是选择还是输入 名字按照antd组件名字传入
     *     label        | string    | 标题
     *     required     | boolean   | 是否必填项  true / false
     *     placeholder  | string    | 描述
     *     parameter    | string    | 参数名字
     *     options      | array     | 如果type为Select必须传,否则认为此组件是Input
     *     pattern      |           | 正则
     *   }]  
     *   onSubmit       | function  | 提交方法
     *   onReset        | function  | 重置方法
     * */
    

    以上就是现阶段组件的全部参数
    由于我们没有把每行显示的个数抛出去,而且在组件内部定义好的3,所有当我们拿到items数组的时候就能知道,我们需要几行才能够显示
    其中this.colLength=3;

     //根据items长度判断需要显示几行
      getChildren(items, getFieldDecorator) {
        const len = items.length;
        const rowLen = Math.ceil(len / this.colLength);
        let rowArr = [];
        for (let i = 0, j = rowLen; i < j; i++) {
          rowArr.push(
            <Row key={i}>
              {
                this.getColItem(items, getFieldDecorator, i)
              }
            </Row>
          );
        }
        return rowArr;
      }
    

    判断每行里边有几个组件比较步骤多一些,不多说直接贴代码就不多说了,直接看源码,其中就是把数组里边的对象正确的显示

    import React, {Component} from 'react';
    import {
      Form,
      Row,
      Col,
      Input,
      Select,
      Button,
      DatePicker,
    } from 'antd';
    
    const FormItem = Form.Item;
    const Option = Select.Option;
    const {RangePicker} = DatePicker;
    
    /**
     *   lixin 2013.4.19
     *   items [{     | array     | 数组包含元素对象
     *   type         | string    | 类型 判断是选择还是输入 名字按照antd组件名字传入
     *   label        | string    | 标题
     *   required     | boolean   | 是否必填项  true / false
     *   placeholder  | string    | 描述
     *   parameter    | string    | 参数名字
     *   options      | array     | 如果type为Select必须传,否则认为此组件是Input
     *   pattern      |           | 正则
     *   typeDiff     | boolean      | true type为Select的时候,key为string的时候会用到
     *   }]
     *   onSubmit     | function  | 提交方法
     *   onReset      | function  | 重置方法
     *   未完待续...
     *
     * */
    @Form.create()
    class Search extends Component {
      
      constructor(props) {
        
        super(props);
        
        this.colLength = 3;//每行显示个数,暂时因为栅格布局不能修改
      }
      
      
      //根据items长度判断需要显示几行
      getChildren(items, getFieldDecorator) {
        
        
        const len = items.length;
        const rowLen = Math.ceil(len / this.colLength);
        
        
        let rowArr = [];
        for (let i = 0, j = rowLen; i < j; i++) {
          rowArr.push(
            <Row key={i}>
              
              {
                this.getColItem(items, getFieldDecorator, i)
              }
            
            </Row>
          );
        }
        
        return rowArr;
        
        
      }
      
      
      //为每行里边塞Col
      getColItem(items, getFieldDecorator, start) {
        
        const colArr = [];
        
        const _this = this;
        
        //从items数组第几个元素开始循环
        const _start = start * this.colLength;
        
        //剩余几个对象没有遍历渲染
        const _surplus = items.length - _start;
        
        let len;
        //如果剩下的小于3 长度直接登录items的长度
        if (_surplus < this.colLength) {
          len = items.length;
        } else {
          //如果剩下的大于3,那么长度等于开始索引加3
          len = _start + this.colLength;
        }
        
        for (let i = _start, j = len; i < j; i++) {
          const index = i;
          const value = items[i];
          const _offset = index % this.colLength == 0 ? 0 : 1;
          
          let _type = value.type;
          
          let _options;
          if (value.hasOwnProperty('options')) {
            _options = value.options;
          } else {
            if (_type === 'RangePicker') {
              //
            } else {
              _type = 'Input';
            }
            
          }
          
          let _rulesType = 'number';
          
          if (_type === 'Input') {
            _rulesType = 'string';
            
          } else if (_type === 'RangePicker') {
            _rulesType = 'array';
          }
          
          if (value.typeDiff) {
            _rulesType = 'string';
          }
          
          const formItemLayout = {
            labelCol: {
              span: 8,
            },
            wrapperCol: {
              span: 16,
            },
          };
          colArr.push(
            <Col key={index} xl={{span: 7, offset: _offset}} lg={{span: 8}} md={{span: 12}} sm={24}>
              <FormItem label={`${value.label}:`} {...formItemLayout}>
                {getFieldDecorator(value.parameter, {
                  rules: [{
                    required: value.required,
                    message: value.placeholder,
                    pattern: value.pattern ? value.pattern : '',
                    type: _rulesType
                  }]
                })(
                  _this.switchItem(_type, value.placeholder, _options)
                )}
              
              </FormItem>
            </Col>
          )
          
        }
        
        
        return colArr;
        
      }
      
      //如果是Select需要传入options
      switchItem(which, placeholder, options) {
        const _this = this;
        switch (which) {
          
          case 'Input':
            return <Input placeholder={placeholder}/>
          case 'Select':
            return <Select placeholder={placeholder}>{_this.getOption(options)}</Select>
          case 'RangePicker':
            return <RangePicker/>
        }
      }
      
      getOption(data) {
        
        if (!data) {
          return;
        }
        
        return data.map((value, index) => {
          return <Option key={index} value={value.key}>{value.value}</Option>
        })
      }
      
      //重置输入框内容
      handleReset = () => {
        this.props.form.resetFields();
        if (this.props.onReset) {
          this.props.onReset();
        }
      }
      
      //提交
      handleSubmit = (e) => {
        e.preventDefault();
        this.props.form.validateFields((err, fieldsValue) => {
          
          this.props.onSubmit(err, fieldsValue);
          
        });
        
        
      };
      
      render() {
        
        const {items, form, loading} = this.props;
        const {getFieldDecorator} = form;
        
        return (
          <Form onSubmit={this.handleSubmit} layout="horizontal">
            
            {
              this.getChildren(items, getFieldDecorator)
            }
            
            <Row type="flex" justify="end">
              <Col>
                <FormItem>
                  <Button type="default" htmlType="button" style={{marginRight: '10px'}} onClick={this.handleReset}>
                    重置
                  </Button>
                  <Button loading={loading} type="primary" htmlType="submit">
                    查询
                  </Button>
                </FormItem>
              </Col>
            
            </Row>
            {
              this.props.children
            }
          </Form>
        )
      }
    }
    
    
    export default Search;
    
    
    其中比较特殊的就是当type为Select的时候,这个时候必须传参数options(array)数组,因为下来菜单我们要有选项集,如果不传我们默认它是一个Input组件

    相关文章

      网友评论

      本文标题:Ant Design Pro开发后台管理系统(Search)

      本文链接:https://www.haomeiwen.com/subject/gnfsgftx.html