react+antd樹選擇下拉框中增加搜索框
react antd樹選擇下拉框中增加搜索框
ant Design提供的樹選擇提供了搜索功能,但是這個(gè)搜索功能是在樹選擇的選擇框內(nèi),現(xiàn)在的需求是要把搜索功能抽離到下拉框中。(官方提供的方法是只要加上showSearch就可以實(shí)現(xiàn)搜索功能)。
function AdvancedSelect(props) {
? const [treeData] = props; // 下拉框數(shù)據(jù)
? const [searchValue, setSearchValue] = useState(''); // 搜索框值
? const [val, setVal] = useState([]); // 樹選擇框的值
? // 搜索框的值發(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)搜索框沒有值的時(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('')} // 展開下拉菜單的回調(diào)
? ? ? ? dropdownRender={(menu) => (
? ? ? ? ? <>
? ? ? ? ? ? <Input
? ? ? ? ? ? ? onChange={handleChangeSearch}
? ? ? ? ? ? ? value={searchValue}
? ? ? ? ? ? ? placeholder="請(qǐng)搜索"
? ? ? ? ? ? />
? ? ? ? ? ? {menu}
? ? ? ? ? </>
? ? ? ? )} // 自定義下拉框內(nèi)容
? ? ? ? onChange={handleChange}
? ? ? ? treeNodeFilterProp: 'title' // 輸入項(xiàng)過濾對(duì)應(yīng)的 treeNode 屬性
? ? ? ? placeholder: '請(qǐng)選擇'
? ? ? />
? ? </div>
? );
}這里的樹選擇下拉框的數(shù)據(jù)是從其他組件傳遞過來的,格式為:
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簡單封裝antd的樹形下拉框
該組件的功能有
1.可設(shè)置搜索功能
2.可以每級(jí)可選,也可以選擇只能最后一級(jí)里面的選項(xiàng)可選
3.當(dāng)組件是只能最后一級(jí)里面的選項(xiàng)可選時(shí), 點(diǎn)擊文字展開下級(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)過濾對(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的簡單使用
?<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ù)中的開發(fā)需求,需要的朋友可以參考下2022-07-07
ForwardRef?useImperativeHandle方法demo
這篇文章主要為大家介紹了ForwardRef?useImperativeHandle方法demo,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03
詳解React中的setState執(zhí)行機(jī)制
setState是React組件中用于更新狀態(tài)的方法,是類組件中的方法,用于更新組件的狀態(tài)并重新渲染組件,本文給大家詳細(xì)介紹了React中的setState執(zhí)行機(jī)制,文中通過代碼示例介紹的非常詳細(xì),需要的朋友可以參考下2023-12-12
react學(xué)習(xí)每天一個(gè)hooks?useWhyDidYouUpdate
這篇文章主要為大家介紹了react學(xué)習(xí)每天一個(gè)hooks?useWhyDidYouUpdate使用示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04
react項(xiàng)目打包后點(diǎn)擊index.html頁面出現(xiàn)空白的問題
這篇文章主要介紹了react項(xiàng)目打包后點(diǎn)擊index.html頁面出現(xiàn)空白的問題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06
Remix后臺(tái)開發(fā)之remix-antd-admin配置過程
這篇文章主要為大家介紹了Remix后臺(tái)開發(fā)之remix-antd-admin配置過程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04
React路由規(guī)則定義與聲明式導(dǎo)航及編程式導(dǎo)航分別介紹
這篇文章主要介紹了React路由規(guī)則的定義、聲明式導(dǎo)航、編程式導(dǎo)航,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2022-09-09
JavaScript React如何修改默認(rèn)端口號(hào)方法詳解
這篇文章主要介紹了JavaScript React如何修改默認(rèn)端口號(hào)方法詳解,文中通過步驟圖片解析介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(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

