React-Component-Library--Select

该文章展示了如何使用React创建一个自定义的Select下拉选择组件,包括配置选项、宽高、禁用状态、加载状态、搜索功能和清除选项等特性。代码中使用了useRef、useState、useEffect等ReactHooks进行状态管理和DOM操作。
摘要由CSDN通过智能技术生成

 

 

Select下拉选择

使用以及文档如图:

 

 

 

封装代码如下所示 

import React, { FC, useMemo, createRef, useEffect, useState, useCallback, memo } from 'react';
import { DownOutlined, LoadingOutlined, CloseOutlined } from '@ant-design/icons';
import './index.module.less';

interface Options {
  label: String | number;
  value: String | number;
  disabled?: Boolean;
}
interface SelectProps {
  /**
   * @description 选择器数据
   * @default []
   */
  option: Array<Options>;
  /**
   * @description 宽度
   * @default 80px
   */
  width?: Number;
  /**
   * @description 提示
   * @default false
   */
  placeholder?: String;
  /**
   * @description 禁用状态
   * @default false
   */
  disabled?: Boolean;
  /**
   * @description 加载状态
   * @default false
   */
  loading?: Boolean;
  /**
   * @description 可输入状态
   * @default false
   */
  showSearch?: Boolean;
  /**
   * @description 可输入状态下清除
   * @default false
   */
  clearable?: Boolean;
  /**
   * @description 选择后的回调
   * @default {}
   */
  handleSelectCallback?: Function;
  /**
   * @description 输入后的回调
   * @default {}
   */
  handleTextChange?: Function;
}

const Select: FC<SelectProps> = (props) => {
  const {
    option,
    width,
    placeholder,
    disabled,
    loading,
    showSearch,
    clearable,
    handleSelectCallback,
    handleTextChange,
  } = props;
  const [selected, setSelected] = useState<string | number | any>('');
  const optionRef = createRef() as any;

  useEffect(() => {
    optionRef.current.height = `0px`;
    console.log(option);
  }, []);

  const ownsWidth = useMemo(() => {
    //传参宽度
    if (width) {
      return {
        width: `${width}px`,
      };
    }
    return {};
  }, [width]);
  const disabledStyle = useMemo(() => {
    //禁用状态
    if (disabled) {
      return {
        cursor: 'not-allowed',
        background: 'rgb(238, 238, 238)',
      };
    }
  }, [disabled]);

  const toggleOptions = (e: any) => {
    //切换下拉
    e.stopPropagation();
    if (disabled) return;
    console.log(optionRef.current.style.height);
    if (optionRef.current.style.height === '0px' || optionRef.current.style.height === '') {
      if (showSearch) {
        optionRef.current.style.height = `${inputFilterOtpions.length * 100}%`;
      } else {
        optionRef.current.style.height = `${option.length * 100}%`;
      }
    } else {
      optionRef.current.style.height = '0px';
    }
    console.log(optionRef.current.height);
  };
  const changeOptions = (v: Options, e: any) => {
    //选择选项
    e.stopPropagation();
    if (v.disabled) return;
    optionRef.current.style.height = '0px';
    setSelected(v.label);
    if (handleSelectCallback) {
      handleSelectCallback(v.value);
    }
  };
  const inputFilterOtpions = useMemo(() => {
    //输入状态options过滤
    return option.filter((item) => {
      return (item.label as string).includes(selected);
    });
  }, [option, selected]);
  const handleInputChange = useCallback(
    (e: any) => {
      //输入后的回调
      setSelected(e.target.value);
      optionRef.current.style.height =
        option.filter((item) => {
          return (item.label as string).includes(e.target.value);
        }).length *
          100 +
        '%';
      if (handleTextChange) {
        handleTextChange(e.target.value);
      }
    },
    [selected],
  );

  return showSearch ? (
    <>
      <div className="select" style={{ ...ownsWidth, ...disabledStyle }}>
        <div className="selected">
          <input
            type="text"
            className="selected"
            value={selected}
            placeholder={placeholder as string}
            onClick={toggleOptions}
            onChange={(e) => handleInputChange(e)}
          />
          {clearable ? (
            <CloseOutlined onClick={() => setSelected('')} />
          ) : (
            <DownOutlined onClick={toggleOptions} />
          )}
        </div>
        <div className="selectOptions" style={ownsWidth} ref={optionRef}>
          {inputFilterOtpions.map((s) => {
            return (
              <div
                key={s.label as any}
                className="option"
                style={
                  s.disabled ? { cursor: 'not-allowed', background: 'rgb(238, 238, 238)' } : {}
                }
                onClick={(e) => changeOptions(s as Options, e)}
              >
                {s.label}
              </div>
            );
          })}
        </div>
      </div>
    </>
  ) : (
    <div className="select" style={{ ...ownsWidth, ...disabledStyle }}>
      <div className="selected" onClick={toggleOptions}>
        {selected ? (
          <div className="size">{selected}</div>
        ) : (
          (placeholder && <div className="placeholder">{placeholder}</div>) || <div />
        )}
        {loading ? <LoadingOutlined /> : <DownOutlined />}
      </div>
      <div className="selectOptions" style={ownsWidth} ref={optionRef}>
        {option.map((s) => {
          return (
            <div
              key={s.label as any}
              className="option"
              style={s.disabled ? { cursor: 'not-allowed', background: 'rgb(238, 238, 238)' } : {}}
              onClick={(e) => changeOptions(s as Options, e)}
            >
              {s.label}
            </div>
          );
        })}
      </div>
    </div>
  );
};
export default memo(Select);

GitHub-address:

https://github.com/username-boy/react-component-library-view/https://github.com/username-boy/react-component-library-view/icon-default.png?t=N5K3https://github.com/username-boy/react-component-library-view/

good  luck !

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值