Antd搜索栏组件SearchForm的封装/使用

后台管理系统都会用到如页头搜索栏以及table展示数据,为了减少代码量以及尽量公用部分逻辑,集成对应控件并统一封装成一个组件显得十分有必要。

功能

组件依赖于moment,使用demo依赖loadsh做防抖。
先展示功能部分。

/**
 * 
 * @param {页面搜索栏组件} form 前端chen
 * ----避免各个页面的搜索栏各自为战的问题,统一组件,减少代码量,尽量逻辑/组件复用----
 * 兼容的搜索控件:
    ===Button:可以添加多个button按钮;
    ===Input:基本使用,输入框;
    ===InputNumber:number输入框;
    ===AutoComplete:输入匹配输入框,匹配规则默认option.props.children.toUpperCase().indexOf(inputValue.toUpperCase()) !== -1;
    ===Select:下拉选择器,传递selectList{id,name}或者render=>reactNode生成对应的下拉框内容; 
    ===TreeSelect:同·Select·;
    ===Switch:开关按钮,默认文字为“开/关”;
    ===Cascader:级联选择器,例如省市区;
    ===WeekPicker:星期选择器;
    ===MonthPicker:月份选择器;
    ===DatePicker:日期选择器;
    ===RangePicker:日期间隔选择器;
    ===TimeRangePicker:基于timepicker二次封装的时间段选择器,onChange时额外返回permission,开始/结束时间都有值以及autoSearch时触发搜索;
*                 
* 使用规则:除了各个组件使用原有API,新增如下API
    ===searchList:搜索栏list,其中三个字段必填:tagName标签名称,key搜索键值名称,label搜索前置名称 ;
    ===reset:是否重置按钮,boolean值,默认true ;
    ===onChange:每个非button控件值改变时触发的操作,function(itemValue); 
    ===onDateChange:对应日期/时间选择器相关onchange[moment,str]事件,方便获取对应的str,会先于onChange执行
    ===onSearch:触发搜索,function(fieldsValue);
    ===autoSearch:是否自动触发搜索,boolean值,默认false ;
    ===noSearchButton:是否不用搜索按钮,boolean值,默认false ;
    ===stopPagination:是否返回true禁止其他如table的分页器关联操作, function(boolean) ;
    ===onButtonClick:有其他额外button按钮时触发的操作,function(item); 
*                     
*/

Demo

接着看下使用demo

import React, { PureComponent } from "react";
import { debounce } from "lodash"; // 防抖

import { SearchForm } from "@/components";

const searchList = [
  {
    tagName: "treeselect",
    key: "treeSelectItem",
    label: "类型",
    defaultValue: null,
    placeholder: "请选择",
    selectList: [
      {
        id: 0,
        name: "123",
        children: [
          {
            id: 10,
            name: "12311"
          },
          {
            id: 11,
            name: "asd11"
          }
        ]
      },
      {
        id: 1,
        name: "asd"
      }
    ]
  },
  {
    tagName: "select",
    key: "selectItem",
    label: "类型2",
    defaultValue: null,
    placeholder: "请选择",
    render: () => {
      // render权限比selectList高
      return [
        {
          id: 0,
          name: "12311"
        },
        {
          id: 1,
          name: "asd111"
        }
      ].map(item => {
        return (
          
        );
      });
    },
    selectList: [
      {
        id: 0,
        name: "123"
      },
      {
        id: 1,
        name: "asd"
      }
    ]
  },
  {
    tagName: "autoComplete",
    key: "autoCompleteItem",
    label: "标题",
    dataSource: ["Burns Bay Road", "Downing Street", "Wall Street"]
  },
  {
    tagName: "TimeRangePicker",
    key: "timerangepickerItem",
    label: "时间",
    timeRange: {
      startTime: "00:10:00",
      endTime: "00:20:00"
    }
  }
];

export function SearchFormFunctionDemo() {
  const onSearch = e => {
    console.log(e);
  };
  return (
     console.log(e), 1500)}
      onSearch={debounce(e => onSearch(e), 350)}
      onChange={debounce(e => console.log(e), 350)}
    />
  );
}

export class SearchFormClassDemo extends PureComponent {
  constructor(props) {
    super(props);
    this.onSearch = debounce(this.onSearch, 350);
  }

  onSearch = e => {
    console.log(e);
  };

  render() {
    return (
       console.log(e)}
        onSearch={e => this.onSearch(e)}
        onChange={e => console.log(e)}
      />
    );
  }
}

实现封装

最后看下封装代码,其中TimeRangePicker是之前就封装好的组件,可以看下另外一篇文章

import React, { Fragment } from "react"; 
import moment from "moment";

import {
  Icon,
  Button,
  Input,
  InputNumber,
  AutoComplete,
  Select,
  message,
  DatePicker,
  TreeSelect,
  Switch,
  Cascader,
  TimePicker,
  Form
} from "antd";

import { TimeRangePicker } from "@/components";

const FormItem = Form.Item;
const { Option } = Select;
const { TreeNode } = TreeSelect;
const { MonthPicker, RangePicker, WeekPicker } = DatePicker;

/**
 * 
 * @param {页面搜索栏组件} form chenhaoyin
 * ----避免各个页面的搜索栏各自为战的问题,统一组件,减少代码量,尽量逻辑/组件复用----
 * 兼容的搜索控件:
    ===Button:可以添加多个button按钮;
    ===Input:基本使用,输入框;
    ===InputNumber:number输入框;
    ===AutoComplete:输入匹配输入框,匹配规则默认option.props.children.toUpperCase().indexOf(inputValue.toUpperCase()) !== -1;
    ===Select:下拉选择器,传递selectList{id,name}或者render=>reactNode生成对应的下拉框内容; 
    ===TreeSelect:同·Select·;
    ===Switch:开关按钮,默认文字为“开/关”;
    ===Cascader:级联选择器,例如省市区;
    ===WeekPicker:星期选择器;
    ===MonthPicker:月份选择器;
    ===DatePicker:日期选择器;
    ===RangePicker:日期间隔选择器;
    ===TimeRangePicker:基于timepicker二次封装的时间段选择器,onChange时额外返回permission,开始/结束时间都有值以及autoSearch时触发搜索;
*                 
* 使用规则:除了各个组件使用原有API,新增如下API
    ===searchList:搜索栏list,其中三个字段必填:tagName标签名称,key搜索键值名称,label搜索前置名称 ;
    ===reset:是否重置按钮,boolean值,默认true ;
    ===onChange:每个非button控件值改变时触发的操作,function(itemValue); 
    ===onDateChange:对应日期/时间选择器相关onchange[moment,str]事件,方便获取对应的str,会先于onChange执行
    ===onSearch:触发搜索,function(fieldsValue);
    ===autoSearch:是否自动触发搜索,boolean值,默认false ;
    ===noSearchButton:是否不用搜索按钮,boolean值,默认false ;
    ===stopPagination:是否返回true禁止其他如table的分页器关联操作, function(boolean) ;
    ===onButtonClick:有其他额外button按钮时触发的操作,function(item); 
*                     
*/

/** formItem的getFieldDecorator配置 */
const getFieldDecoratorOps = form => {
  let rules = null;
  if (form.rules) {
    rules = [...form.rules];
  }
  if (form.pattern) {
    rules = [
      {
        pattern: form.pattern,
        message: form.message || "内容不符合规则"
      }
    ];
  }
  return {
    initialValue: form.nextdefaultvalue || form.nextvalue,
    rules
  };
};

const Search = ({
  searchList /** 搜索栏list,其中三个字段必填:tagName标签名称,key搜索键值名称,label搜索名称 */,
  reset = true /** 重置按钮 */,
  onDateChange /** 日期相关onchange[str,moment]事件,方便获取对应的str */,
  onSearch /** 触发搜索 */,
  autoSearch /** 自动触发搜索 */,
  noSearchButton /** 不用搜索按钮 */,
  stopPagination /** 是否返回true禁止其他如table的分页器关联操作 */,
  onButtonClick /** 有其他额外button按钮时触发的操作 */,
  form: { getFieldDecorator, validateFields, setFieldsValue, resetFields }
}) => {
  if (!searchList) {
    searchList = [];
  }

  /** 搜索 */
  const handleSearch = () => {
    validateFields((err, fieldsValue) => {
      // console.log(err);
      // console.log(fieldsValue);
      if (!err) {
        stopPagination && stopPagination(false);
      } else {
        message.destroy();
        message.error("搜索条件有误", 1.5);
        stopPagination && stopPagination(true);
      }
      onSearch && onSearch(fieldsValue);
    });
  };

  /** 获取时间段 */
  const getRangeTime = (key, range, permission) => {
    const time = [range.startTime, range.endTime, permission];
    const fields = {
      [key]: time
    };
    setFieldsValue(fields);
    range.startTime && range.endTime && autoSearch && handleSearch();
  };

  /** datePicer衍生器onchange */
  const dateChange = (mo, str) => {
    onDateChange && onDateChange([str, mo]);
    autoSearch && handleSearch();
  };

  return (
    
{searchList.map((form, idx) => { if (!form.tagName) { return console.error("请使用tagName作为控件的标签名字段"); } form = { ...form, nextvalue: form.value || form.checked, // 新增字段要用小写,不然会警告 nextdefaultvalue: form.defaultValue || form.defaultChecked // 新增字段要用小写,不然会警告 }; const exp = form.pattern; const tagname = form.tagName; const Options = getFieldDecoratorOps(form); delete form.checked; delete form.defaultChecked; // delete form.dataSource; delete form.pattern; // 警告:pattern命名会和组件本身冲突,但为了更友好继续沿用此命名 delete form.tagName; // 警告:在react中属性都是小驼峰命名,所以也会有属性的命名冲突 delete form.value; // 警告:如果有改属性,{...form}会与getFieldDecorator产生冲突 delete form.defaultValue; // 警告:如果有改属性,{...form}会与getFieldDecorator产生冲突 return ( {tagname.toLowerCase() === "input" && getFieldDecorator(form.key, Options)( handleSearch()} suffix={} {...form} /> )} {tagname.toLowerCase() === "inputnumber" && getFieldDecorator(form.key, Options)( handleSearch()} suffix={} {...form} c /> )} {tagname.toLowerCase() === "autocomplete" && getFieldDecorator(form.key, Options)( option.props.children .toUpperCase() .indexOf(inputValue.toUpperCase()) !== -1 } onSearch={() => handleSearch()} onSelect={() => autoSearch && handleSearch()} // onSearch={() => handleSearch()} {...form} /> )} {tagname.toLowerCase() === "switch" && getFieldDecorator(form.key, { ...Options, valuePropName: "checked" })( autoSearch && handleSearch()} {...form} /> )} {tagname.toLowerCase() === "select" && getFieldDecorator(form.key, Options)( )} {tagname.toLowerCase() === "treeselect" && getFieldDecorator(form.key, Options)( autoSearch && handleSearch()} {...form} > {form.render && form.render()} {!form.render && (form.selectList || []).map(cl => { return ( {(cl.children || []).map(chil => { return ( ); })} ); })} )} {tagname.toLowerCase() === "datepicker" && getFieldDecorator(form.key, Options)( dateChange(date, str)} {...form} /> )} {tagname.toLowerCase() === "weekpicker" && getFieldDecorator(form.key, Options)( dateChange(week, str)} {...form} /> )} {tagname.toLowerCase() === "monthpicker" && getFieldDecorator(form.key, Options)( dateChange(mon, str)} {...form} /> )} {tagname.toLowerCase() === "rangepicker" && getFieldDecorator(form.key, Options)( dateChange(range, str)} style={{ width: "230px" }} {...form} /> )} {tagname.toLowerCase() === "timepicker" && getFieldDecorator(form.key, Options)( dateChange(date, str)} {...form} /> )} {tagname.toLowerCase() === "timerangepicker" && getFieldDecorator(form.key, Options)( {/* 因为TimeRangePicker本身是平级双标签生成, 所以必须要有外层标签包裹,否则无效 */} getRangeTime(form.key, range, permission) } /> )} {tagname.toLowerCase() === "cascader" && getFieldDecorator(form.key, Options)( )} {tagname.toLowerCase() === "button" && getFieldDecorator(form.key, Options)( )} ); })} {!noSearchButton && ( )} {reset && ( )}
); }; Search.propTypes = {}; export const SearchForm = Form.create({ name: "SearchForm", // onFieldsChange(props, changedFields) { /** 有多少个item会执行多少次 */ // props.onChange && props.onChange(changedFields); // }, // mapPropsToFields(props) { // // 对props做处理 // console.log(props); // }, onValuesChange(props, values, e) { /** 只会执行一次 */ props.onChange && props.onChange(values); } })(Search);

你可能感兴趣的:(Antd搜索栏组件SearchForm的封装/使用)