React + Antd + Ts 自定义Select选择框 全选功能(两种不同样式)
- 第一种默认样式
import React from 'react';
import { Select, Checkbox } from 'antd';
const { Option } = Select;
interface Option {
label: string;
value: string;
}
interface SelectProps {
options: Option[];
}
const SelectWithCheckbox: React.FC<SelectProps> = ({ options }) => {
const [selectedValues, setSelectedValues] = React.useState<string[]>([]);
const handleSelectChange = (values: string[]) => {
setSelectedValues(values);
};
return (
<Select
style={{ width: 400 }}
mode="multiple"
onChange={handleSelectChange}
maxTagCount={3}
value={selectedValues}
dropdownRender={(menu) => (
<div>
<div onClick={(e) => e.stopPropagation()}>
// 因为option.value可能为undefined,但是这里不允许undefined,所以加!
<a
onClick={() =>
handleSelectChange(options.map((option) => option.value!))
}
style={{ display: 'block', margin: '10px 10px' }}
>
选择所有
</a>
</div>
{menu}
</div>
)}
>
{options.map((option) => (
<Option key={option.value} value={option.value}>
{option.label}
</Option>
))}
</Select>
);
};
export default SelectWithCheckbox;
-
第二种带复选框的选择框(带搜索)
import React , {useState} from 'react'; import { Select, Checkbox,Empty } from 'antd'; import './index.less'; const { Option } = Select; interface Option { label: string; value: string; } interface SelectProps { options: Option[]; style?: React.CSSProperties; placeholder?: string; onChange?: (values: string[]) => void; } const SelectWithCheckbox: React.FC<SelectProps> = ({ options, style, placeholder, onChange, }) => { const [selectedValues, setSelectedValues] = useState<string[]>([]); const [searchKeyword, setSearchKeyword] = useState(''); const [isSearchEmpty, setIsSearchEmpty] = useState(false); const handleSelectChange = (values: string[]) => { setSelectedValues(values); searchKeyword && setSearchKeyword(''); onChange && onChange(values); }; const handleSearch = (value: string) => { setSearchKeyword(value); setIsSearchEmpty( options.filter((option) => option.label.toLowerCase().includes(value.toLowerCase()), ).length === 0, ); }; const handleAllOptionSelect = ( event: React.ChangeEvent<HTMLInputElement>, ) => { if (event.target.checked) { handleSelectChange(options.map((option) => option.value!)); } else { handleSelectChange([]); } }; const isAllOptionSelected = () => { const selectedOptions = options .filter( (option) => option.value !== undefined && option.value !== null && option.value !== '', ) .map((option) => option.value!); return ( selectedOptions.length > 0 && selectedOptions.every((value) => selectedValues.indexOf(value) !== -1) ); }; return ( <Select style={{ width: '100%', ...style }} placeholder={placeholder} className="select-with-checkbox" mode="multiple" onChange={handleSelectChange} value={selectedValues} onSearch={(value) => handleSearch(value)} maxTagCount={3} getPopupContainer={(triggerNode) => triggerNode.parentNode} maxTagPlaceholder={(omittedValues) => `+ ${omittedValues.length} 项`} dropdownRender={(menu) => ( <div className="my-select-wrapper"> {!searchKeyword && ( <div onClick={(e) => e.stopPropagation()} className="my-menu-all"> <Checkbox checked={isAllOptionSelected()} onChange={handleAllOptionSelect as any} style={{ width: '100%', padding: '5px 20px' }} > 全部 </Checkbox> </div> )} {isSearchEmpty ? ( <div className="my-empty"> <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} /> </div> ) : ( options .filter((option) => option.label .toLowerCase() .includes(searchKeyword.toLowerCase()), ) .map((option) => ( <div key={option.value} onClick={(e) => e.stopPropagation()} className="my-menu-item" > <Checkbox checked={selectedValues.indexOf(option.value) !== -1} onChange={(e) => { const nextSelectedValues = e.target.checked ? [...selectedValues, option.value] : selectedValues.filter( (value) => value !== option.value, ); handleSelectChange(nextSelectedValues); }} style={{ width: '100%', padding: '5px 20px' }} > {option.label} </Checkbox> </div> )) )} </div> )} > {options.map((option) => ( <Option key={option.value} value={option.value}> {option.label} </Option> ))} </Select> ); }; export default SelectWithCheckbox;
index.less 样式文件
.select-with-checkbox { .ant-select-selector { height: 36px; border: 1px solid #ebebeb !important; border-radius: 6px !important; .ant-select-selection-item { height: 25px; background: #f2f9ff; border-radius: 4px 4px 4px 4px; border: 1px solid #a0d1ff; .ant-select-selection-item-content { display: flex; align-items: center; color: #1f91fc; } .ant-select-selection-item-remove { font-size: 12px; &:hover { color: #1e91fe; } } } } } .my-select-wrapper { max-height: 320px; overflow-y: auto; } .my-menu-all { cursor: pointer; &:hover { font-weight: 600; background-color: #f5f5f5; } .ant-checkbox-wrapper-checked { font-weight: 600; background-color: #e6f7ff; } } .my-menu-item { cursor: pointer; &:hover { font-weight: 600; background-color: #f5f5f5; } .ant-checkbox-wrapper-checked { font-weight: 600; background-color: #e6f7ff; } }