自定义组件下拉搜索选择框

最终效果:

自定义组件下拉搜索选择框_第1张图片自定义组件下拉搜索选择框_第2张图片

 

代码如下

interface

export interface IFilter {
    /** unique id */
    id: string;
    /** machine serial number */
    machineSn: string;
    /** if value is true, user select this data  */
    checked: boolean;
}

component

import * as React from "react";
import {IFilters} from "./IFilters";
import "../../public/style/Filter.scss";

interface IFilterProps {
  filters?: IFilters[];
  filterUpdate?: (arrays: IFilters[]) => void;
}
interface IFilterState {
  checkAll: boolean;
  displayDialog: boolean;
  listOfFilters: IFilters[];
  queryInputValue: string;
  metadataList: IFilters[];
}
export class MachineSnFilter extends React.Component {
  constructor(props: IFilterProps) {
    super(props);
    this.state = {
      checkAll: false,
      displayDialog: false,
      listOfFilters: [],
      queryInputValue: "",
      metadataList: [],
    };
    this.changeQueryInputValue = this.changeQueryInputValue.bind(this);
    this.checkAllFilters = this.checkAllFilters.bind(this);
    this.cancelOperation = this.cancelOperation.bind(this);
    this.filterOnCheckChange = this.filterOnCheckChange.bind(this);
    this.saveFilters = this.saveFilters.bind(this);
    this.makePropsDataToState = this.makePropsDataToState.bind(this);
  }

  public render() {
    const dialogClassName = this.state.displayDialog
      ? "filter-dialog"
      : "filter-dialog filter-dialog-hidden";
    return (
      
{/* switch button */} {this.switchButtonRender()} {/* dialog */}
{/* check all */}
{this.checkAllCheckboxRender()} {this.closeIconRender()}
{/* input */} {this.queryInputBoxRender()} {/* checkbox */}
{this.machineSnFiltersRender()}
{/* button( save/ cancel ) */}
); } public componentDidMount() { this.makePropsDataToState(); } public componentDidUpdate(nextProps) { if (this.props.filters !== nextProps.filters) { this.makePropsDataToState(); } } /** when component will un mount, reset all state */ public componentWillUnmount() { if (this.props.filters) { const checkAll = this.isCheckAll(this.props.filters); this.setState({ checkAll, displayDialog: false, listOfFilters: this.props.filters, queryInputValue: "", metadataList: this.props.filters, }); } } /** render toggle button */ private switchButtonRender() { return (
{ this.setState({displayDialog: !this.state.displayDialog}); }}>
打开
{/* arrow */} arrow
); } /** render checkbox of 'checkAll' */ private checkAllCheckboxRender() { return ( <>
checkAll icon {this.state.checkAll ? "uncCheck all" : "check all"}
); } /** render close icon , when click this icon, close dialog */ private closeIconRender() { return ( close icon ); } /** render query input box */ private queryInputBoxRender() { return (
); } /** render list of machineSn filter items */ private machineSnFiltersRender() { return this.state.listOfFilters.map((e, index) => (
check icon {e.machineSn}
)); } /** merge props 'filters' to state */ private makePropsDataToState() { const newArr: IFilters[] = []; if (this.props.filters) { this.props.filters.forEach(item => { newArr.push(item); }); } const checkAll = this.isCheckAll(newArr); this.setState({listOfFilters: newArr, metadataList: newArr, checkAll}); } /** user input field changed, change state 'checkAll','listOfFilters' */ private changeQueryInputValue(event) { const value = event.target.value; this.setState({queryInputValue: value}, () => { const {metadataList} = {...this.state}; const newArr = metadataList.filter(item => item.machineSn.includes(value)); const checkAll = this.isCheckAll(newArr); this.setState({ checkAll, listOfFilters: newArr, }); }); } /** make all machineSn filter items are selected, or make all items are unselected */ private checkAllFilters() { this.setState({checkAll: !this.state.checkAll}, () => { const newArr: IFilters[] = []; this.state.listOfFilters.forEach(item => { item = {...item, checked: this.state.checkAll ? true : false}; newArr.push(item); }); const checkAll = this.isCheckAll(newArr); const newSaveItems = this.changeItemsCheckedProperty(this.state.metadataList, newArr); this.setState({ checkAll, listOfFilters: newArr, metadataList: newSaveItems, }); }); } /** * user select machineSn filters, change state 'listOfFilters' and 'checkAll' 'metadata' * @param e:`IFilters` filter item selected by the user */ private filterOnCheckChange(e) { const filterArr: IFilters[] = [ { ...e, checked: !e.checked, }, ]; const newListOfItems = this.changeItemsCheckedProperty(this.state.listOfFilters, filterArr); const checkAll = this.isCheckAll(newListOfItems); const newSaveItems = this.changeItemsCheckedProperty(this.state.metadataList, filterArr); this.setState({ checkAll, listOfFilters: newListOfItems, metadataList: newSaveItems, }); } /** * change specified items property of 'checked' in old list, return new list of items * @param arr: `IFilters[]` old list of items * @param filterArr: `IFilters[]` specified items */ private changeItemsCheckedProperty(arr: IFilters[], filterArr: IFilters[]) { const newArr = [...arr]; for (let i = 0; i < newArr.length; i++) { for (let j = 0; j < filterArr.length; j++) { let item: IFilters = newArr[i]; if (newArr[i].id === filterArr[j].id) { item = { ...newArr[i], checked: filterArr[j].checked, }; // replace selected item newArr.splice(i, 1, item); } } } return newArr; } /** * * if value equal true, there are some item are unselected * * if value equal false, all item are selected * @param itemList: `IFilters[]` List of data to traverse */ private isCheckAll(itemList: IFilters[]) { const unSelectedItems = itemList.filter(e => e.checked === false); if (unSelectedItems.length === 0 && itemList.length !== 0) { return true; } return false; } /** save machineSn filters selected by the user, update metadata, close dialog */ private saveFilters() { if (this.props.filterUpdate) { this.props.filterUpdate(this.state.metadataList); } this.setState({ displayDialog: false, queryInputValue: "", }); } /** close dialog of machineSn filters, reset state */ private cancelOperation() { let checkAll = false; let listOfFilters: IFilters[] = []; let metadataList: IFilters[] = []; if (this.props.filters) { checkAll = this.isCheckAll(this.props.filters); listOfFilters = this.props.filters; metadataList = this.props.filters; } this.setState({ checkAll, displayDialog: false, listOfFilters, queryInputValue: "", metadataList, }); } }

scss

%filter-input {
  width: 1rem;
  height: 1rem;
  cursor: pointer;
}
%filter-input-label {
  margin-left: 0.6rem;
  cursor: pointer;
}
// flex layout
%filter-flex {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
// button color
$filter-color: #dcdcdc;
// border width
$filter-width: 0.1rem;
.filters {
  margin-top: 2rem;
  position: relative;
  label {
    margin: 0;
  }
  // switch button
  .filter-word {
    cursor: pointer;
    width: 10rem;
    padding: 0.6rem 1rem;
    border: $filter-width solid black;
    font-size: 1.125rem;
    @extend %filter-flex;
    .filter-arrow {
      width: 1.125rem;
      height: 1.125rem;
    }
    .filter-arrowUp {
      transform: rotate(180deg);
    }
  }
  //   dialog
  .filter-dialog {
    display: block;
    background-color: white;
    width: 26rem;
    height: 25rem;
    border: $filter-width solid black;
    position: absolute;
    z-index: 5;
    top: 3.1rem;
    left: 0;
    text-align: center;
    // check all
    .filter-checkAll-label {
      @extend %filter-flex;
      height: 3rem;
      padding: 0 1rem;
      border-bottom: $filter-width solid $filter-color;
      .filter-checkAll-image {
        @extend %filter-input;
      }
      .filter-checkAll-word {
        @extend %filter-input-label;
      }
      // close icon
      .filter-closeIcon {
        display: inline-block;
        width: 2rem;
        height: 2rem;
        cursor: pointer;
      }
    }
    // input
    .filter-queryInput {
      line-height: 3rem;
      text-align: left;
      padding-left: 1rem;
      border-bottom: $filter-width solid $filter-color;
      .filter-queryInput-input {
        height: 2rem;
        outline: none;
        border: $filter-width solid #d9d9d9;
        padding-left: 2rem;
        box-sizing: border-box;
        border-radius: 0.4rem;
        &:hover {
          outline: none;
          border: $filter-width solid #40a9ff;
        }
        &:focus {
          outline: none;
          border: $filter-width solid #40a9ff;
          box-shadow: 0 0 0 0.12rem rgba(24, 144, 255, 0.2);
        }
      }
    }
    // checkbox
    .filter-checkbox-part {
      height: 15rem;
      overflow-y: auto;
      border-bottom: $filter-width solid $filter-color;

      .filter-checkbox {
        display: flex;
        padding: 0.7em 0 0.8rem 1rem;
        align-items: center;
        &:hover {
          background-color: $filter-color;
        }
        .filter-checkbox-image {
          @extend %filter-input;
        }
        .filter-checkbox-word {
          @extend %filter-input-label;
        }
      }
    }
    // button(save/cancel)
    .filter-button {
      margin-top: 1rem;
      .filter-button-save,
      .filter-button-cancel {
        border: 0;
        background-color: $filter-color;
        margin: 0 1rem;
        padding: $filter-width 1rem;
        width: 6rem;
        text-overflow: ellipsis;
        white-space: nowrap;
        overflow: hidden;
        &:hover {
          background-color: #cfcfcf;
        }
      }
    }
  }
  .filter-dialog-hidden {
    display: none;
  }
}

svg

arrow.svg

checkIcon.svg

closeIcon.svg

unCheckIcon.svg

 

你可能感兴趣的:(自定义组件下拉搜索选择框)