react+antd树选择下拉框中增加搜索框
作者:司宁
这篇文章主要介绍了react+antd树选择下拉框中增加搜索框方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
react antd树选择下拉框中增加搜索框
ant Design提供的树选择提供了搜索功能,但是这个搜索功能是在树选择的选择框内,现在的需求是要把搜索功能抽离到下拉框中。(官方提供的方法是只要加上showSearch就可以实现搜索功能)。
function AdvancedSelect(props) { const [treeData] = props; // 下拉框数据 const [searchValue, setSearchValue] = useState(''); // 搜索框值 const [val, setVal] = useState([]); // 树选择框的值 // 搜索框的值发生改变searchValue值也跟着改变 const handleChangeSearch = (e) => { setSearchValue(e.target.value || ''); }; // 下拉数据二级处理 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; }; // 处理下拉框数据 const formatTreeData = () => { // 当搜索框没有值的时候不做处理 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('')} // 展开下拉菜单的回调 dropdownRender={(menu) => ( <> <Input onChange={handleChangeSearch} value={searchValue} placeholder="请搜索" /> {menu} </> )} // 自定义下拉框内容 onChange={handleChange} treeNodeFilterProp: 'title' // 输入项过滤对应的 treeNode 属性 placeholder: '请选择' /> </div> ); }
这里的树选择下拉框的数据是从其他组件传递过来的,格式为:
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.可设置搜索功能
2.可以每级可选,也可以选择只能最后一级里面的选项可选
3.当组件是只能最后一级里面的选项可选时, 点击文字展开下级选项
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 = '请选择', 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数据,为对象数组 * 隐藏掉指定value的选项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 ? '' : '请选择'); 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'}//输入项过滤对应的 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数据示例
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 />
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。