美文网首页
Antd搜索组件Filter封装

Antd搜索组件Filter封装

作者: 郁南 | 来源:发表于2020-07-02 21:25 被阅读0次

    早期有封装过js版本Antd搜索栏组件SearchForm的封装/使用

    介绍

    组件封装的初衷,当然都是为了代码尽可能的复用,从Jquery时代的commonjs就有的模块化思想,在react上应该体现的是最淋漓尽致的。
    日常后台页面开发,基本上都会有增删改查,所以把常用功能整合起来并封装成公用组件就显得十分有必要。

    封装

    由于新项目都使用TS,所以就用在js版本基础上优化并使用ts。下面是实现代码

    import React from "react";
    import {
      Form,
      Row,
      Col,
      Input,
      Button,
      InputNumber,
      AutoComplete,
      Select, 
      DatePicker,
      TreeSelect,
      Switch,
      Cascader,
      TimePicker,
    } from "antd"; // antd@4.x
    const { RangePicker } = DatePicker; 
    
    import { setKeystoLocaleLowerCase } from "@/utils"; // 避免引起命名冲突,把oject的key都转化为小写
    
    const { Option } = Select;
    const { TreeNode } = TreeSelect;
    
    interface FilterProps {
      filterList: any[];
      autoSearch?: boolean;
      onSearch?: Function;
      onReset?: Function;
      [key: string]: any;
    }
    
    export const Filter = ({
      filterList,
      autoSearch = false,
      onSearch,
      onReset,
      ...props
    }: FilterProps) => {
      const [form] = Form.useForm();
      filterList = setKeystoLocaleLowerCase(filterList);
    
      const onFinish = (values: { [key: string]: string | number | undefined }) => {
        onSearch && onSearch(values);
      };
    
      const lisLen: number = filterList.length;
      const span: number = lisLen >= 5 ? 4 : (24 - 2.5) / lisLen;
    
      const getFormElement = (tagname: string, oItem: any) => {
        /** onPressEnter会自动执行 */
        let item: any = {};
        for (let key in oItem) {
          if (oItem.hasOwnProperty(key)) {
            if (key !== "defaultvalue") {
              item[key] = oItem[key];
            }
          }
        }
        item = {
          ...item,
          onChange: () => autoSearch && onFinish(form.getFieldsValue()),
          onSelect: () => autoSearch && onFinish(form.getFieldsValue()),
        };
        switch (tagname) {
          case "input":
            return <Input allowClear {...item} />;
          case "inputnumber":
            return <InputNumber min={0} {...item} />;
          case "autocomplete": 
            return (
              <AutoComplete
                allowClear
                options={item.options}
                filterOption={(inputValue: any, option: any) => {
                  return (
                    option.value.toUpperCase().indexOf(inputValue.toUpperCase()) !==
                    -1
                  );
                }}
                {...item}
              />
            );
          case "switch": 
            return <Switch checkedChildren="开" unCheckedChildren="关" {...item} />;
          case "select":
            const selectlist = item.list || item.selectlist || []; 
            return (
              <Select allowClear {...item}>
                {item.render && item.render()}
                {!item.render &&
                  selectlist.map((cl: any) => {
                    const oName = cl.key || cl.text || cl.name;
                    return (
                      <Option key={cl.id} value={cl.id}>
                        {oName}
                      </Option>
                    );
                  })}
              </Select>
            );
          case "treeselect":
            const treeSelectList = item.list || item.selectlist || []; 
            return (
              <TreeSelect allowClear multiple {...item}>
                {item.render && item.render()}
                {!item.render &&
                  treeSelectList.map((cl: any) => {
                    const nodeName = cl.key || cl.text; 
                    return (
                      <TreeNode key={cl.id} value={cl.id} title={nodeName}>
                        {(cl.children || []).map((chil: any) => {
                          const subnodeName = chil.key || chil.text; 
                          return (
                            <TreeNode
                              key={chil.id}
                              value={chil.id}
                              title={subnodeName}
                            />
                          );
                        })}
                      </TreeNode>
                    );
                  })}
              </TreeSelect>
            );
          case "datepicker":
            return <DatePicker {...item} />;
          case "rangepicker":
            return <RangePicker {...item} />;
          case "timepicker":
            return <TimePicker {...item} />;
          case "rangetimepicker":
            return <TimePicker.RangePicker {...item} />;
          case "cascader":
            return <Cascader {...item} />;
          default:
            return "";
        }
      };
    
      return (
        <Form
          form={form}
          name="advanced_search"
          className="ant-advanced-search-form"
          {...props}
          onFinish={onFinish}
        >
          <Row gutter={24}>
            {filterList.map((item: any, i: number) => {
              const tagname = (item.tagname || "").toLowerCase();
    
              if (tagname !== "input" && item.rules) {
                // delete item.rules;
                item.rules = null;
              }
    
              const itemName = item.key; 
              return (
                <Col
                  span={tagname === "switch" ? 2.5 : span}
                  key={item.key + i}
                  style={{
                    minWidth: tagname === "switch" ? "auto" : "200px", 
                  }}
                >
                  <Form.Item
                    name={itemName}
                    label={item.label}
                    rules={item.rules ? [item.rules] : []}
                  >
                    {getFormElement(tagname, item)}
                  </Form.Item>
                </Col>
              );
            })}
    
            <Col
              span={2.5}
              style={{ minWidth: "100px", textAlign: "right", flex: "auto" }}
            >
              <Button type="primary" htmlType="submit">
                查询
              </Button>
              <Button
                style={{ margin: "0 8px" }}
                onClick={() => {
                  form.resetFields();
                  onReset && onReset();
                }}
              >
                重置
              </Button>
            </Col>
          </Row>
        </Form>
      );
    };
    

    这样组件就满足了大部分的使用场景,有需要的,就再迭代新增就好了,需要做的兼容也不是很多

    使用

    在日常开发,应该把模块化思想最大化的落实到项目上,所以页面实现不管是组件还是业务,我都喜欢按功能拆分

    1. 初始数据
    // ./initData.ts
    export const filterList = [
      {
        tagName: "input",
        key: "name",
        label: "模糊搜索",
        placeholder: "请输入姓名/ID/手机后4位/站点地址",
      },
      {
        tagName: "datepicker",
        key: "datepickerItem",
        label: "创建日期",
      },
      {
        tagName: "select",
        key: "site",
        label: "站点",
        defaultValue: null,
        placeholder: "请选择站点",
        selectList: [
          {
            id: 0,
            name: "站点1",
          },
          {
            id: 1,
            name: "站点2",
          },
        ],
      },
      {
        tagName: "treeselect",
        key: "state",
        label: "状态",
        defaultValue: null,
        placeholder: "请选择状态",
        selectList: [
          {
            id: 0,
            name: "状态1",
            children: [
              {
                id: 10,
                name: "状态11",
              },
              {
                id: 11,
                name: "状态12",
              },
            ],
          },
          {
            id: 1,
            name: "状态2",
            children: [
              {
                id: 20,
                name: "状态21",
              },
              {
                id: 21,
                name: "状态22",
              },
            ],
          },
        ],
      },
    ];
    
    1. 页面
    import React, { FC } from "react";
    
    import { Filter } from "@/components";
    
    import { filterList} from "./initData";
    
    export const FilterDemo: FC<any> = () => {
      const onSearch = (values: any) => {
        console.log(values);
      };
    
      return (
        <div> 
          <Filter
            filterList={filterList}
            onSearch={(values: any) => onSearch(values)}
          />
    
          {/* 其他业务组件 */}
        </div>
      );
    }
    

    这样这个Filter组件基本上就可以随处可用了
    如果对组件封装以及性能优化等有更好的建议,欢迎在评论区留言

    相关文章

      网友评论

          本文标题:Antd搜索组件Filter封装

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