react+antd 开发一个可动态增减的复合组件

需求如图:

 

 

与后端协商好的表单数据为:

 

 

组件代码:

/* 阶梯分成组件 */
import React, { useState, useEffect } from 'react';
import { message, InputNumber, Button } from 'antd';
import { PlusOutlined, DeleteOutlined } from '@ant-design/icons';
import styles from './Condition.less';

let rowKey = 0;

type ConfigProps = {
  unit?: string;
  afterText?: string;
  precision?: number;
  key?: string;
};

const Condition: React.FC<any> = (props) => {
  const { value, maxLength, config, onChange } = props;
  const [dataList, setDataList] = useState<any[]>([{ rowKey }]);

  // 新增
  const handleAdd = () => {
    if (dataList && dataList.length <= maxLength) {
      if (!rowKey) rowKey = dataList.length || 0;
      rowKey += 1;
      const keyObj = {};
      config.map((item: ConfigProps) => {
        if (item.key) keyObj[item.key] = undefined;
      });
      const newObj = { ...keyObj, rowKey };
      setDataList([...dataList, newObj]);
      if (onChange) {
        onChange([...dataList, newObj]);
      }
    } else {
      message.error('已达添加上限');
    }
  };

  // 删除
  const handleDelete = (_key: any) => {
    setDataList(dataList.filter((it: any) => it.rowKey !== _key));
    if (onChange) {
      onChange(dataList.filter((it: any) => it.rowKey !== _key));
    }
  };

  // 要求整数
  // const limitDecimals = (values?: string | number | undefined) => {
  //   if (values) return String(values).replace(/^(0+)|[^\d]+/g, '');
  //   return '';
  // };

  // 改变值
  const handleNumber = (_value: number | string | null, data: any, key: string) => {
    const newList = dataList.map((it) => {
      if (it.rowKey === data.rowKey) {
        return { ...it, [key]: _value };
      }
      return it;
    });
    setDataList(newList);
    if (onChange) {
      onChange(newList);
    }
  };

  // 监听默认值更新
  useEffect(() => {
    if (value && value.length > 0) {
      setDataList(value);
    }
  }, []);

  return (
    <div
      className={styles['m-condition']}
      style={{
        maxHeight: dataList.length > 10 ? '432px' : 'auto',
        overflowY: dataList.length > 10 ? 'scroll' : 'auto',
      }}
    >
      {dataList &&
        dataList.map((item: any, index: number) => (
          <div key={`${item.rowKey}${item.tips}`} style={{ marginBottom: '8px' }}>
            <div
              style={{
                width: '100%',
                display: 'flex',
                justifyContent: 'flex-start',
                alignItems: 'center',
              }}
            >
              {config?.map((itemConfig: any, indexConfig: number) => {
                return (
                  <span
                    key={itemConfig.afterText}
                    style={{ display: 'inline-flex', alignItems: 'center' }}
                  >
                    <InputNumber
                      max={
                        indexConfig === 0 ? item[config[1].key] || itemConfig.max : itemConfig.max
                      }
                      min={
                        indexConfig === 1 ? item[config[0].key] || itemConfig.min : itemConfig.min
                      }
                      style={{
                        width: '140px',
                        marginLeft: indexConfig === 0 ? 0 : '8px',
                        marginRight: '8px',
                      }}
                      precision={itemConfig.precision}
                      placeholder={'请输入'}
                      value={itemConfig.num}
                      onChange={(values) => handleNumber(values, item, itemConfig.key)}
                      key="NumberMin"
                      addonAfter={itemConfig.unit}
                    />
                    <span>{itemConfig.afterText}</span>
                  </span>
                );
              })}
              <DeleteOutlined
                onClick={() => handleDelete(item.rowKey)}
                style={{ marginLeft: '8px', visibility: index === 0 ? 'hidden' : 'visible' }}
              />
            </div>
          </div>
        ))}
      <Button
        type="dashed"
        onClick={handleAdd}
        style={{ width: '100%' }}
        icon={<PlusOutlined />}
        disabled={maxLength && dataList && dataList.length && dataList.length >= maxLength}
      >
        新增阶梯
      </Button>
    </div>
  );
};

export default Condition;

  

.m-condition {
  &::-webkit-scrollbar {
    width: 4px;
  }

  &::-webkit-scrollbar-thumb {
    background: #e3e8ee;
    border-radius: 10px;
  }

  &::-webkit-scrollbar-track-piece {
    background: transparent;
  }
}

  

引用:

在存储表单组件的dataSource数组时,遍历render:
if (el.id === 'xxx') {
            return {
              ...el,
              renderFormItem: () => <Condition />,
            };
          }

 

传递的数据格式为:

 

 

 

 

 

 

posted @ 2022-10-21 14:33  芝麻小仙女  阅读(281)  评论(0编辑  收藏  举报