React 基础下拉菜单组件(select)

1,246 阅读2分钟

前言

因为做的是大屏的项目,样式要和大屏的颜色相同,所以就自己写了一个简易的select组件,还参考了ant design的select组件实现了下拉菜单在展开时点击其他地方自动收起下拉菜单。 ps:当然没有ant那么的复杂,主要使用了contains方法。

contains

这是IE的方法,其他浏览器也有支持,唯一不支持这个方法的是firefox。如果A元素包含B元素,则返回true,否则false。。

tsx

import { useState, useEffect, useRef } from 'react';
interface selectProps {
  option: any;
  defaultValue: string;
  selectStyle?: object;
  onSelect?: Function;
}
const Select = (props: selectProps) => {
  const { option } = props;
  const { defaultValue, selectStyle, onSelect } = props;
  let [checked, setChecked] = useState(false);
  let [value, setValue] = useState(defaultValue);
  let selectRef = useRef<HTMLDivElement>(null);
  useEffect(() => {
    const selectCheck = (e: any) => {
      if (!(selectRef.current as HTMLDivElement).contains(e.target)) {
        console.log('select元素不包含点击元素', selectRef.current, e.target);
        setChecked(false);
      }
    };
    document.addEventListener('click', selectCheck);
    return () => document.removeEventListener('click', selectCheck);
  }, []);
  // 点击显示下拉菜单
  const checkedItem = (e: any) => {
    console.log('checkedItem', checked);

    // e.stopPropagation();
    if (checked) {
      setChecked(false);
    } else {
      setChecked(true);
    }
  };
  // 点击option触发
  const checkedOption = (e: any) => {
    setValue(e.target.innerText);
    onSelect && onSelect(e.target.innerText);
    setChecked(false);
  };

  return (
    <>
      <div
        className={style.cSelect}
        style={selectStyle}
        ref={selectRef}
        onClick={checkedItem}
      >
        <div className={style.select}>
          <div className={style.selectItem}>
            <div className={style.defaultValue}>
              <div className={style.value}>{value}</div>
              {!checked ? (
                <div className={style.downLined}></div>
              ) : (
                <div className={style.upLined}></div>
              )}
            </div>
            {checked
              ? option.map((item: string, index: number) => {
                  return (
                    <div
                      className={style.option}
                      key={index}
                      onClick={checkedOption}
                    >
                      {item}
                    </div>
                  );
                })
              : null}
          </div>
        </div>
      </div>
    </>
  );
};

export default Select;

less

  position: relative;
  width: 180px;
  height: 100%;
  .select {
    position: absolute;
    z-index: 999;
    width: 100%;
    border-radius: 10px;
    background: #051f52;
    .selectItem {
      width: 100%;
      font-size: 14px;
      padding: 0 7px;
      cursor: pointer;
      background: linear-gradient(
        180deg,
        rgba(17, 130, 229, 0.4),
        rgba(16, 129, 228, 0) 49%,
        rgba(17, 130, 228, 0.4)
      );
      border: 1px solid #1079d8;
      border-radius: 10px;
      .value {
        color: #fff;
      }
      .defaultValue {
        width: 100%;
        height: 32px;
        display: flex;
        justify-content: center;
        align-items: center;
        .downLined {
          width: 0;
          height: 0;
          border-right: 5px solid transparent;
          border-left: 5px solid transparent;
          border-top: 8px solid #1084e8;
          margin-left: 10px;
        }
        .upLined {
          width: 0;
          height: 0;
          border-right: 5px solid transparent;
          border-left: 5px solid transparent;
          border-bottom: 8px solid #1084e8;
          margin-left: 10px;
        }
      }
      .option {
        width: 100%;
        height: 32px;
        padding: 0 10px;
        border-top: 0.5px solid #106ec8;
        line-height: 32px;
      }
    }

    .noOption {
      display: none;
    }
  }
}