react+antd樹(shù)選擇下拉框中增加搜索框
react antd樹(shù)選擇下拉框中增加搜索框
ant Design提供的樹(shù)選擇提供了搜索功能,但是這個(gè)搜索功能是在樹(shù)選擇的選擇框內(nèi),現(xiàn)在的需求是要把搜索功能抽離到下拉框中。(官方提供的方法是只要加上showSearch就可以實(shí)現(xiàn)搜索功能)。
function AdvancedSelect(props) { ? const [treeData] = props; // 下拉框數(shù)據(jù) ? const [searchValue, setSearchValue] = useState(''); // 搜索框值 ? const [val, setVal] = useState([]); // 樹(shù)選擇框的值 ? // 搜索框的值發(fā)生改變searchValue值也跟著改變 ? const handleChangeSearch = (e) => { ? ? setSearchValue(e.target.value || ''); ? }; ? // 下拉數(shù)據(jù)二級(jí)處理 ? const formatChildTreeData = (data, result) => { ? ? data.forEach((cur) => { ? ? ? if (cur.title.includes(searchValue)) { ? ? ? ? result.push(cur); ? ? ? } else if (cur.children && cur.children.length) { ? ? ? ? const childResult = formatChildTreeData(cur.children, result); ? ? ? ? if (childResult.length) { ? ? ? ? ? result.push({ ? ? ? ? ? ? ...cur, ? ? ? ? ? ? children: childResult, ? ? ? ? ? }); ? ? ? ? } ? ? ? } ? ? }); ? ? return result; ? }; ? // 處理下拉框數(shù)據(jù) ? const formatTreeData = () => { ? ? // 當(dāng)搜索框沒(méi)有值的時(shí)候不做處理 ? ? if (!searchValue) return treeData; ? ? const result = []; ? ? treeData.forEach((item) => { ? ? ? if (item.title.includes(searchValue)) { ? ? ? ? result.push(item); ? ? ? } else if (item.children && item.children.length) { ? ? ? ? const childResult: ITreeDataItem[] = formatChildTreeData( ? ? ? ? ? item.children, ? ? ? ? ? [], ? ? ? ? ); ? ? ? ? if (childResult.length) { ? ? ? ? ? result.push({ ? ? ? ? ? ? ...item, ? ? ? ? ? ? children: childResult, ? ? ? ? ? }); ? ? ? ? } ? ? ? } ? ? }); ? ? return result; ? }; ? const handleChange = (changedValue) => { ? ? const _val = changedValue.map((item) => item.value); ? ? setVal(_val); ? }; ? return ( ? ? <div> ? ? ? <TreeSelect ? ? ? ? style={{ ? ? ? ? ? width: '100%', ? ? ? ? }} ? ? ? ? value={val} ? ? ? ? treeData={formatTreeData()} ? ? ? ? treeCheckable //顯示 Checkbox ? ? ? ? onDropdownVisibleChange={() => setSearchValue('')} // 展開(kāi)下拉菜單的回調(diào) ? ? ? ? dropdownRender={(menu) => ( ? ? ? ? ? <> ? ? ? ? ? ? <Input ? ? ? ? ? ? ? onChange={handleChangeSearch} ? ? ? ? ? ? ? value={searchValue} ? ? ? ? ? ? ? placeholder="請(qǐng)搜索" ? ? ? ? ? ? /> ? ? ? ? ? ? {menu} ? ? ? ? ? </> ? ? ? ? )} // 自定義下拉框內(nèi)容 ? ? ? ? onChange={handleChange} ? ? ? ? treeNodeFilterProp: 'title' // 輸入項(xiàng)過(guò)濾對(duì)應(yīng)的 treeNode 屬性 ? ? ? ? placeholder: '請(qǐng)選擇' ? ? ? /> ? ? </div> ? ); }
這里的樹(shù)選擇下拉框的數(shù)據(jù)是從其他組件傳遞過(guò)來(lái)的,格式為:
const treeData = [ ? { ? ? title: 'Node1', ? ? value: '0-0', ? ? key: '0-0', ? ? children: [ ? ? ? { ? ? ? ? title: 'Child Node1', ? ? ? ? value: '0-0-0', ? ? ? ? key: '0-0-0', ? ? ? }, ? ? ], ? }, ? { ? ? title: 'Node2', ? ? value: '0-1', ? ? key: '0-1', ? ? children: [ ? ? ? { ? ? ? ? title: 'Child Node3', ? ? ? ? value: '0-1-0', ? ? ? ? key: '0-1-0', ? ? ? }, ? ? ? { ? ? ? ? title: 'Child Node4', ? ? ? ? value: '0-1-1', ? ? ? ? key: '0-1-1', ? ? ? }, ? ? ? { ? ? ? ? title: 'Child Node5', ? ? ? ? value: '0-1-2', ? ? ? ? key: '0-1-2', ? ? ? }, ? ? ], ? }, ];
react簡(jiǎn)單封裝antd的樹(shù)形下拉框
該組件的功能有
1.可設(shè)置搜索功能
2.可以每級(jí)可選,也可以選擇只能最后一級(jí)里面的選項(xiàng)可選
3.當(dāng)組件是只能最后一級(jí)里面的選項(xiàng)可選時(shí), 點(diǎn)擊文字展開(kāi)下級(jí)選項(xiàng)
import React, { ReactNode, useEffect, useState } from 'react'; import { Form, TreeSelect } from 'antd'; import _, { get, isEmpty } from 'lodash'; import styles from './SimpleTreeSelect.module.css'; import { arrayLengthMoreThanZero } from 'utils/formatHelper'; import './SimpleTreeSelect.css'; interface ITreeSelectProps { label: string; name: any; required?: boolean; errorMessage?: string; placeHolder?: string; optionValue?: string; optionLabel?: string; value?: string; width?: string; addAll?: boolean; allOption?: object; labelStyle?: React.CSSProperties; containerStyle?: React.CSSProperties; disabled?: boolean; showSearch?: boolean; onChange?: (value: string, arg2?: ReactNode[], arg3?: any) => void; onFocus?: (arg: any) => void; allLabel?: string; allValue?: string; hideOptionValue?: string | string[]; validator?: (arg1: any, arg2: any) => any; bottomContent?: string | JSX.Element; showArrowIcon?: boolean; option: ItreeNodeItem[]; onLoadData?: (arg: any) => any; allCanSelect?: boolean; } interface ItreeNodeItem { id?: string; pId?: string; value?: string; title?: string; disabled?: boolean; isLeaf?: boolean; } export const SimpleTreeSelect = (props: ITreeSelectProps) => { const { label, name, required = false, errorMessage = '必選', // placeHolder = '請(qǐng)選擇', value, option: initOption, width = 290, addAll = true, labelStyle, containerStyle, disabled = false, allOption, onChange, showSearch = true, allLabel = '全部', allValue = '', hideOptionValue, validator, bottomContent = '', showArrowIcon = true, onFocus, onLoadData, allCanSelect = false, } = props; const [option, setOption] = useState<any[]>(initOption); /** * option: select數(shù)據(jù),為對(duì)象數(shù)組 * 隱藏掉指定value的選項(xiàng)hideOptionValue * */ useEffect(() => { if (allCanSelect) return; const option: any[] = initOption; for (let item of option) { const arr = (option || []).filter(its => get(its, ['pId']) === get(item, ['id'])) || []; item.disabled = arrayLengthMoreThanZero(arr); } if (addAll) { option.unshift({ pId: allValue, value: allValue, title: allLabel, }) } if (typeof hideOptionValue === 'string' && hideOptionValue) { const idx = _.findIndex(option, item => get(item, ['id']) === hideOptionValue); if (idx >= 0) option.splice(idx, 1); } if (arrayLengthMoreThanZero(hideOptionValue)) { const hideOption = hideOptionValue || [] const arr: any[] = _.filter(option, item => { for (let its of hideOption) { if (get(item, ['id']) !== its) return item; } }) || []; setOption(arr); } else { setOption(option); } }, [initOption, hideOptionValue, allCanSelect]); const placeHolder = props.placeHolder || (disabled ? '' : '請(qǐng)選擇'); const renderLabel = () => { return ( <span className={styles.label} style={labelStyle}> {required && <span className={styles.star}>*</span>} {label} </span> ); }; const renderArrowIcon = () => showArrowIcon ? <span className={styles.arrowIcon} /> : <></>; return ( <div style={containerStyle} className={styles.selectContainer}> <Form.Item colon={false} label={renderLabel()}> <Form.Item name={name} colon={false} noStyle validateFirst initialValue={value} rules={ validator ? [{ required: required, message: errorMessage }, { validator }] : [{ required: required, message: errorMessage }] } > <TreeSelect treeDataSimpleMode showSearch={showSearch} treeNodeFilterProp={'title'}//輸入項(xiàng)過(guò)濾對(duì)應(yīng)的 treeNode 屬性, value或者title style={{ width: width && /^\d+$/.test(width.toString()) ? `${width}px` : width }} dropdownStyle={{ maxHeight: 400, overflow: 'auto' }} allowClear treeDefaultExpandAll={false} onChange={(value, label, extra) => { onChange && onChange(value, label, extra) }} onClick={e=> { const vvv:any = e.target||{}; const el:any = get(vvv.parentNode.children, [1]) || get(vvv.parentNode.parentNode.children, [1]); try { if('click' in el) { el.click(); } else { const evt:any = document.createEvent('Event'); evt.initEvent('click', true, true); el.dispatchEvent(evt); } } catch(err) { console.log(err) } }} onFocus={onFocus} loadData={onLoadData} value={value} placeholder={placeHolder} treeData={option} disabled={disabled} suffixIcon={renderArrowIcon()} > </TreeSelect> </Form.Item> {!isEmpty(bottomContent) && <div style={{ margin: 0 }}> <div style={{ marginBottom: '-5px' }}> {bottomContent} </div> </div>} </Form.Item> </div> ); };
treeData數(shù)據(jù)示例
? const arr0 = [ ? ? { ? ? ? id: 1, ? ? ? pId: 0, ? ? ? value: 'leaf-1', ? ? ? title: '屬性圖1' ? ? }, ? ? { ? ? ? id: 2, ? ? ? pId: 1, ? ? ? value: 'leaf-2', ? ? ? title: '屬性圖2' ? ? }, ? ? { ? ? ? id: 3, ? ? ? pId: 0, ? ? ? value: 'leaf-3', ? ? ? title: '屬性圖3' ? ? } ? ]; ? let [treeData, setTreeData] = useState<any[]>(arr0);
CustomSimpleTreeSelect的簡(jiǎn)單使用
?<CustomSimpleTreeSelect ? ? ? ? ? option={treeData} ? ? ? ? ? labelStyle={labelStyle} ? ? ? ? ? containerStyle={containerStyle} ? ? ? ? ? addAll={false} ? ? ? ? ? name="xxx" ? ? ? ? ? label="xxx" ? ? ? ? ? required ? ? ? ? />
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Shopee在React?Native?架構(gòu)方面的探索及發(fā)展歷程
這篇文章主要介紹了Shopee在React?Native?架構(gòu)方面的探索,本文會(huì)從發(fā)展歷史、架構(gòu)模型、系統(tǒng)設(shè)計(jì)、遷移方案四個(gè)方向逐一介紹我們?nèi)绾我徊讲降貪M足多團(tuán)隊(duì)在復(fù)雜業(yè)務(wù)中的開(kāi)發(fā)需求,需要的朋友可以參考下2022-07-07ForwardRef?useImperativeHandle方法demo
這篇文章主要為大家介紹了ForwardRef?useImperativeHandle方法demo,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03詳解React中的setState執(zhí)行機(jī)制
setState是React組件中用于更新?tīng)顟B(tài)的方法,是類組件中的方法,用于更新組件的狀態(tài)并重新渲染組件,本文給大家詳細(xì)介紹了React中的setState執(zhí)行機(jī)制,文中通過(guò)代碼示例介紹的非常詳細(xì),需要的朋友可以參考下2023-12-12react學(xué)習(xí)每天一個(gè)hooks?useWhyDidYouUpdate
這篇文章主要為大家介紹了react學(xué)習(xí)每天一個(gè)hooks?useWhyDidYouUpdate使用示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04react項(xiàng)目打包后點(diǎn)擊index.html頁(yè)面出現(xiàn)空白的問(wèn)題
這篇文章主要介紹了react項(xiàng)目打包后點(diǎn)擊index.html頁(yè)面出現(xiàn)空白的問(wèn)題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06Remix后臺(tái)開(kāi)發(fā)之remix-antd-admin配置過(guò)程
這篇文章主要為大家介紹了Remix后臺(tái)開(kāi)發(fā)之remix-antd-admin配置過(guò)程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04React路由規(guī)則定義與聲明式導(dǎo)航及編程式導(dǎo)航分別介紹
這篇文章主要介紹了React路由規(guī)則的定義、聲明式導(dǎo)航、編程式導(dǎo)航,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2022-09-09JavaScript React如何修改默認(rèn)端口號(hào)方法詳解
這篇文章主要介紹了JavaScript React如何修改默認(rèn)端口號(hào)方法詳解,文中通過(guò)步驟圖片解析介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07使用React Native創(chuàng)建以太坊錢包實(shí)現(xiàn)轉(zhuǎn)賬等功能
這篇文章主要介紹了使用React Native創(chuàng)建以太坊錢包,實(shí)現(xiàn)轉(zhuǎn)賬等功能,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-07-07