Antd搜索组件Filter封装
2020-07-02 本文已影响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>
);
};
这样组件就满足了大部分的使用场景,有需要的,就再迭代新增就好了,需要做的兼容也不是很多
使用
在日常开发,应该把模块化思想最大化的落实到项目上,所以页面实现不管是组件还是业务,我都喜欢按功能拆分
- 初始数据
// ./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",
},
],
},
],
},
];
- 页面
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组件基本上就可以随处可用了
如果对组件封装以及性能优化等有更好的建议,欢迎在评论区留言