React

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > React > react antd树选择下拉框中增加搜索框

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
        />

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文