带有父级的下拉勾选组件的回显与禁用

70 阅读1分钟

20240513201214_rec_.gif 如上大致为需求UI图以及相关操作:

大致思路:需要一个折叠控制组件,以及带有父级勾选的子组件,以及整个界面组件;

折叠控制组件:

//折叠组件
const { isShow: showIcon, changeStatus: handleToogleIcon } = useToogleStatus(true);
<ToggleIcon show={showIcon} toggleList={handleToogleIcon}></ToggleIcon>
 import { useState } from 'react';

export const useToogleStatus = (intial: boolean) => {
  const [isShow, setIsShow] = useState<boolean>(intial);
  const changeStatus = () => {
    setIsShow(!isShow);
  };
  return {
    isShow,
    changeStatus,
  };
};
import styles from './index.scss';

export interface IProps {
  show: boolean;
  toggleList: () => void;
}
const ToggleIcon = (props: IProps) => {
  return (
    <>
      <div className={styles['label-title']} onClick={props.toggleList}>
        <div
          className={
            props.show ? styles['labelTitleIconShow'] : styles['labelTitleIconHide']
          }></div>
      </div>
    </>
  );
};

export default ToggleIcon;
@mixin box-common {
  width: 0;
  height: 0;
  margin-left: 5px;
  margin-top: 5px;
  cursor: pointer;
  border: 4px solid transparent;
}

.label-title {
  font-size: 14px;
  font-weight: 700;
  padding: 10px 0;
  margin-top: 10px;
  margin-right: 5px;
  cursor: pointer;
  .labelTitleIconShow {
    @include box-common;
    border-top: 6px solid #c3cad9;
  }
  .labelTitleIconHide {
    @include box-common;
    border-left: 6px solid #c3cad9;
  }
}

带有父级的勾选子组件


export interface LabelValueType {
  label: string;
  value: string;
}

export interface IConcernedOption {
  label: string;
  value: string;
  isPrimaryKey: boolean;
}
export const VariableCheckbox = (props: {
  form: FormInstance<any>;
  checkAllName: LabelValueType;
  plainOptions: IConcernedOption[];
  isSearch: boolean;
  curOptionsValueList: string[];
  defaultCheckedList: string[];
}) => {
  const { isShow: showIcon, changeStatus: handleToogleIcon } = useToogleStatus(true);

  const [checkAll, setCheckAll] = useState<boolean>(false);
  const [indeterminateStatus, setIndeterminateStatus] = useState<boolean | undefined>(false);
  const onChange = () => {
    const selectdValue = props.form.getFieldValue('concernVars');
    const list = Object.keys(pickBy(selectdValue, (value) => value));
    const curCheckboxSelected = list.filter((varItem) =>
      props.curOptionsValueList.includes(varItem),
    );
    setIndeterminateStatus(
      curCheckboxSelected.length > 0 && curCheckboxSelected.length < props.plainOptions.length,
    );
    setCheckAll(props.plainOptions.length === curCheckboxSelected.length);
  };

  const onCheckAllChange: CheckboxProps['onChange'] = (e) => {
    const checkStatus = e.target.checked;
    setCheckAll(checkStatus);
    props.plainOptions.forEach((optionsItem) => {
      if (!optionsItem.isPrimaryKey)
        props.form.setFieldValue(['concernVars', optionsItem.value], checkStatus);
    });
    const checklist = checkStatus
      ? props.plainOptions.map((optionsItem) => optionsItem.value)
      : props.plainOptions.filter((optionsItem) => optionsItem.isPrimaryKey);
    setIndeterminateStatus(checklist.length > 0 && !checkStatus);
  };

  /** 勾选值回显 */
  useEffect(() => {
    if (props.defaultCheckedList.length) {
      props.defaultCheckedList.forEach((keyItem: string) => {
        props.form.setFieldValue(['concernVars', keyItem], true);
      });

      setCheckAll(props.defaultCheckedList.length === props.plainOptions.length);
      setIndeterminateStatus(
        props.defaultCheckedList.length > 0 &&
          props.defaultCheckedList.length < props.plainOptions.length,
      );
    }
  }, [props.defaultCheckedList]);

  return (
    <>
      <div className={styles['title-container']}>
        <ToggleIcon show={showIcon} toggleList={handleToogleIcon}></ToggleIcon>
          <Checkbox
            indeterminate={indeterminateStatus}
            onChange={onCheckAllChange}
            checked={checkAll}>
            {props.checkAllName.label}
          </Checkbox>
      </div>

      <div style={showIcon ? {} : { display: 'none' }} className={styles['option-container']}>
        <div className={styles['option-container-inner']}>
          {props.plainOptions.map((item) => {
            return (
              <Form.Item
                name={['concernVars', item.value]}
                noStyle
                key={item.value}
                valuePropName="checked">
                {item.isPrimaryKey ? (
                  <Checkbox
                    key={item.value}
                    disabled={item.isPrimaryKey}
                    defaultChecked={item.isPrimaryKey}>
                    {item.label}
                  </Checkbox>
                ) : (
                  <Checkbox key={item.value} onChange={onChange}>
                    {item.label}
                  </Checkbox>
                )}
              </Form.Item>
            );
          })}
        </div>
      </div>
    </>
  );
};

具体使用

{(renderVariableOptions ?? []).map((variableItem, index) => {
              return (
                <VariableCheckbox
                  form={form}
                  checkAllName={variableItem.checkAllName}
                  plainOptions={variableItem.options}
                  key={index}
                  isSearch={isSearch}
                  curOptionsValueList={
                    datasourceVarMap.get(variableItem.checkAllName.value) as string[]
                  }
                  defaultCheckedList={
                    defaultCheckedObj[variableItem.checkAllName.value]
                  }></VariableCheckbox>
              );
            })}