百容千域可以免費做網(wǎng)站嗎上海廣告公司
?1、效果
是你要的效果,咱們繼續(xù)往下看,搜索面板實現(xiàn)省市區(qū)下拉,原本有antd的Cascader組件,但是級聯(lián)組件必須選到子節(jié)點,不能只選省,滿足不了頁面的需求
2、環(huán)境準備
1、react18
2、antd 4+
3、功能實現(xiàn)
原理:封裝一個受控組件,該組件就是兩select基本組件
1、首先,導入需要的組件:
import { Select, Space, Tag } from 'antd';
?2、定義2個狀態(tài)變量來存儲選中省和市的下拉枚舉
const [firstOptions, setFirstOptions] = useState<any>([]);const [secondOptions, setSecondOptions] = useState<any>([]);
?3、組件可接收的props子屬性 如下:
- ?options: 省市級聯(lián)數(shù)據(jù)
- ?value: 已選中的值
- ?width:slect框的寬度
- ?firstPlaceholder 第一個select框的placeholder
- secondPlaceholder第二個select框的placeholder
- ?onChange: 選中的值發(fā)生變化時回調(diào)
?4、創(chuàng)建handleFirstChange函數(shù)來處理第一個select框的change事件,更新第二個select框的下拉項和值
// 第一個select生變化const handleFirstChange = (data: any) => {if (!isEmpty(data) && data.value) {let insertIndex = (options || []).findIndex((item: any) => {return item?.value === data?.value;});setSecondOptions(options?.[insertIndex]?.children || []);onChange({ first: [data] });} else {setSecondOptions([]);onChange(null);}};
?5、創(chuàng)建onSecondChange?函數(shù)來處理第二個select框的change事件,將選中的值回傳給父組件
// 第二個select發(fā)生變化const onSecondChange = (data: any) => {if (!isEmpty(value) && value.first) {if (!isEmpty(data)) {onChange({...value,second: mode === 'multiple' ? (data || []).filter((item: any) => !isNil(item?.label)) : [data],});} else {onChange({ first: value.first, second: null });}} else {onChange(null);}};
?6、最后,使用2個select
組件渲染,并將選中狀態(tài)和change事件綁定到對應(yīng)的屬性上:
return (<><Space wrap={false} direction="horizontal" size={12}><SelectdefaultValue={firstOptions[0]}style={{ width: width }}onChange={handleFirstChange}placeholder={firstPlaceholder || '請選擇'}value={value?.first}options={firstOptions}labelInValueallowClear/><Selectstyle={{ width: width }}value={value?.second || []}onChange={onSecondChange}placeholder={secondPlaceholder || '請選擇'}options={secondOptions}{...mode === "multiple" ? { mode: "multiple", maxTagCount: 'responsive', tagRender: tagRender } : {}}labelInValueallowClear/></Space></>
)
?7、完整代碼如下:
import { Select, Space, Tag } from 'antd';
import clsx from 'clsx';
import { isEmpty, isNil } from 'lodash';
import { useEffect, useState } from 'react';
import './index.less';const MultipleCascaderSelect = (props: any) => {const {options,value,onChange,width = 160,firstPlaceholder,secondPlaceholder,mode = 'multiple'} = props;const [firstOptions, setFirstOptions] = useState<any>([]);const [secondOptions, setSecondOptions] = useState<any>();useEffect(() => {setFirstOptions(options || []);if (Array.isArray(value?.first) && value.first.length) {let findIndex = (options || []).findIndex((item: any) => {return item.value === value.first?.[0].value;});setSecondOptions(options[findIndex]?.children || []);} else {setSecondOptions([]);}}, [options, value]);// 第一個select生變化const handleFirstChange = (data: any) => {if (!isEmpty(data) && data.value) {let insertIndex = (options || []).findIndex((item: any) => {return item?.value === data?.value;});setSecondOptions(options?.[insertIndex]?.children || []);onChange({ first: [data] });} else {setSecondOptions([]);onChange(null);}};// 第二個select發(fā)生變化const onSecondChange = (data: any) => {if (!isEmpty(value) && value.first) {if (!isEmpty(data)) {onChange({...value,second: mode === 'multiple' ? (data || []).filter((item: any) => !isNil(item?.label)) : [data],});} else {onChange({ first: value.first, second: null });}} else {onChange(null);}};const tagRender = ({ label, closable, onClose }: any) => {const isLongTag = `${label}`.length > 4;return (<Tagcolor={label.props?.color}closable={closable}onClose={onClose}className={clsx(['text-sky-400 bg-sky-400/10 text-sm font-normal leading-5',// 'border border-solid border-sky-400/50','max-w-[110px] border-none',// 'whitespace-nowrap text-ellipsis overflow-hidden'])}><span>{isLongTag ? `${label.slice(0, 4)}...` : label}</span>{/* {isLongTag ? (<Tooltiptitle={label}key={label}rootClassName={clsx('toolTipCard')}placement="top"><span>{label.slice(0, 4)}...</span></Tooltip>) : (<span>{label}</span>)} */}</Tag>);};return (<><Space wrap={false} direction="horizontal" size={12}><SelectdefaultValue={firstOptions[0]}style={{ width: width }}onChange={handleFirstChange}placeholder={firstPlaceholder || '請選擇'}value={value?.first}options={firstOptions}labelInValueallowClear/><Selectstyle={{ width: width }}value={value?.second || []}onChange={onSecondChange}placeholder={secondPlaceholder || '請選擇'}options={secondOptions}{...mode === "multiple" ? { mode: "multiple", maxTagCount: 'responsive', tagRender: tagRender } : {}}labelInValueallowClear/></Space></>);
};export default MultipleCascaderSelect;
組件調(diào)用
<MultipleCascaderSelectwidth={162}options={enumData|| []}firstPlaceholder="請選擇"secondPlaceholder="請選擇"/>