定义选中的是id还是name,...rest将其原有的select进行透传
import { Select } from "antd";
import PropTypes from "prop-types";
import { ComponentProps } from "react";
interface Option {
id: string;
name: string;
}
interface MySelectProps {
options: Option[];
valueType?: "id" | "name";
value?: string[];
defaultValue?: string[];
onChange?: (value: string[]) => void;
}
type SelectProps = ComponentProps<typeof Select>;
type Props = MySelectProps & Omit<SelectProps, "value" | "onChange">;
//默认是根据id,可以修改为name
const MySelect: React.FC<Props> = ({ options, valueType = "id", value, onChange, ...rest }) => {
const getValue = (option: Option) => {
return valueType === "id" ? option.id : option.name;
};
const handleChange = (value: string[]) => {
if (onChange) {
onChange(value);
}
};
return (
<Select value={value} onChange={handleChange} {...rest}>
{options.map(option => (
<Select.Option key={option.id} value={getValue(option)}>
{option.name}
</Select.Option>
))}
</Select>
);
};
MySelect.propTypes = {
options: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.string.isRequired,
name: PropTypes.string.isRequired
}).isRequired
).isRequired,
valueType: PropTypes.oneOf(["id", "name"]),
value: PropTypes.arrayOf(PropTypes.string.isRequired),
onChange: PropTypes.func
};
export default MySelect;
使用方法
import MySelect from "@/components/Select/index";
// 多选或者disabled等属性进行透传,类似跟vue的v-bind='$attrs'
<MySelect options={options} valueType="name" mode="multiple" onChange={handleSelectChange} />
const handleSelectChange = (values: string[]) => {
console.log("Selected values:", values);
};
注意点: 类型校验
// 传入的数组可能是空数组,字符串数组,数组对象
options: PropTypes.oneOfType([
PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.string.isRequired,
name: PropTypes.string.isRequired
}).isRequired
),
PropTypes.arrayOf(PropTypes.string.isRequired),
PropTypes.array
]).isRequired,
根据数据不同去渲染
<Select className="mb-10 mr-10" value={value} onChange={handleChange} {...rest} style={{ width: "200px" }}>
{(options as (Option | string)[]).map(option => {
// 空数组或字符串数组
if (!option || typeof option === "string") {
return (
<Select.Option key={option} value={option}>
{option}
</Select.Option>
);
} else {
return (
<Select.Option key={`fragment-${option.id}`} value={getValue(option)}>
{option.name}
</Select.Option>
);
}
})}
</Select>
显示输入框,筛选选项以及输入选项之外的值
(原理就是失去焦点通过onChange传过来的父方法进行setData,要排除一下点击选中选项,这个时候的e.target.value是空,直接返回即可)
<Select className="mb-10 mr-10"
showSearch
value={value}
onChange={handleChange}
onBlur={handleBlur}
{...rest}
style={{ width: "200px" }}
>
const handleBlur = (e: any) => {
if (!e.target.value) return;
// 失去焦点调用父组件的方法进行赋值
handleChange(e.target.value);
};
好了,二次封装的select就满足需求了