在使用antd
的select
组件的时候,由于对lable
扩展或者lable
的复杂化,那么在展示的时候可能有很多lable是一样的,在选择的时候无法区分。所以需要根据属性对options进行过滤。
比如封装后的组件是下图这样的,那么这每一个option
将会是很复杂的。用户在使用的时候可能只记住某一个属性,并且需要根据这个属性进行筛选。比如服务对象,包含服务和端口号,我需要根据协议进行过滤。
那么就需要对select组件
进行扩展,首先分析一下,如果你需要根据属性进行过滤,那么这个option上需要封装相关的属性
。我们知道select中的定义基本是:
{
lable:''
value:''
}
除此之外,因为它本身也是个对象,可以额外添加我们需要的字段属性,比如下图所示,我需要支持hostname,uuid,ip
地址过滤,所以在option中附件了额外的信息:
我们知道在配置页面的下拉数据,一般都是从后台拉取过来的,所以请求回来数据后,重新封装一下就可以了。数据封装完了,可以在官网看到这么个例子检索用户数据
里面给出了动态的向服务端请求数据,但是为了减少服务器的压力,我会在页面加载列表的时候把需要的数据准备好,因为可能在添加/修改
页面都会用到。
数据准备好就可以参考官网给出的列子进行coding了。
别着急动手,在codig之前我们还需要解决一个问题:怎么支持用户根据不同的属性进行过滤呢?
最初的设计是:在提供选择框的同时,给定用户一个选择属性的功能,然后获取到属性和搜索值,记进行匹配。但是想想似乎不太合理,一来页面布局会显得臃肿,二来你需要考虑属性配置的问题,搞起来有点麻烦
。
记得当初使用wireshark
的时候,曾经使用过根据ip过滤
的操作,便想到,其实我们也可以参考这种方式即在select中输入数据各格式为:属性=值,即ip=xx.x.x.x的格式。然后对格式进行处理就可以获取到属性和值
。
如果你使用过qs
和lodash
,那么看到这里,你回很开心。
- qs:可以帮你处理路径参数问题,形如:
ip=xx.x.x.x
通过qs.parse(ip=xx.x.x.x)
,可以自转换为{ip:xx.x.x.x}
的格式- lodash:lodash的filter方法可以根据一个对象去匹配,也就是可以通过{ip:xx.x.x.x}去一个包含ip属性的对象数据中匹配到一致的数据。
- 除此之外你似乎还要考虑防抖的问题,但是在antd中他已经给你做好了,你就不需要处理了。但是一个敏感的前端程序员,应该会想到这个频繁触发导致频繁渲染或者请求的东西,都需要做防抖和节流处理。至于是防抖还是节流,需要你根据业务来判断了。
那么知道这些,我们就可以动手封装这个组件了:
import React, { useState, useMemo } from 'react'
import { Select, Spin } from 'antd';
import { debounce, filter } from 'lodash';
import qs from 'qs'
/**
* 该组件支持属根据属性查询,格式为:属性=值,如ip=xx.x.x.x
* @param {*} props
* @returns
*/
export default function DebounceSelect(props) {
const { fetchOptions } = props
const [fetching, setFetching] = useState(false);
const [options, setOptions] = useState(fetchOptions);
const debounceFetcher = useMemo(() => {
const loadOptions = (query) => {
if (!query) {
setOptions(fetchOptions);
} else {
console.log("查询字符串:", query)
// 将查询数据进行解析
const obj = qs.parse(query)
console.log("解析结果:", obj)
// 根据解析后的数据记进行匹配
const newOptions = filter(fetchOptions, obj)
console.log("匹配到的数据:", newOptions)
setOptions(newOptions);
setFetching(false);
}
};
return debounce(loadOptions, 1000);
}, [fetchOptions]);
/**
* 根据属性去过滤
* @param {*} options 需要过滤的数据
* @param {*} attrs 根据哪些属性去过滤
*/
return (
<Select
mode="multiple"
optionLabelProp="name"
showSearch
filterOption={false}
onSearch={debounceFetcher}
notFoundContent={fetching ? <Spin size="small" /> : null}
{...props}
options={options}
/>
);
}
将该组件导入大到其他组件中使用
<DebounceSelect
value={workload}
onChange={newValue => {
changeW(newValue);
}}
fetchOptions={workloadsT}
/>
当输入这种格式的搜索数据时,就会输出正确的结果。
如果你是自己写的,那么可能会出现匹配到数据时,options跟新了,但是没有正确渲染到select中,那么你可以少了一个属性:filterOption={false}
。否则他会根据输入项筛选,因为它默认值是true
,会根据ip=xx.x.x.x的格式去过滤,它默认的是从label中过滤
。