antd自定义可编辑表格的单元格 EditableProTable

1,216 阅读2分钟

好久都没写过掘金文章了,想来还是找点事做,写写知识点记录一下。

工作中真是频繁用到可编辑表格,最近一次的需求,让我把这个彻底搞明白了。

- 1、合并单元格 这个合并单元格也是常出现的需求,column里面有一个onCell的api可以实现。 我这里合并的条件是id不同且值相同

  const getRowSpan = (record: CollectIQCListType, dataIndex: string) => {
    const value = record[dataIndex];
    let rowSpan = 1;
    for (let i = 0; i < dataSource.length; i++) {
      if (dataSource[i].cacheId !== record.cacheId && dataSource[i][dataIndex] === value) {
        rowSpan++;
      }
    }
    return rowSpan;
  };
  
   {
      title: '检验项目',
      dataIndex: 'programName',
      key: 'programName',
      width: '8%',
      align: 'center',
      editable: false,
      onCell: (record, rowIndex = 0) => ({
        rowSpan:
          rowIndex === 0 || record.programName !== dataSource[rowIndex - 1].programName
            ? getRowSpan(record, 'programName')
            : 0,
      }),
    },

效果:

image.png

- 2、自定义单元格 有一个需求是,数值型的需要根据抽样数去生成输入框,且动态更新不良数,文字类型就显示一个textarea。这样就需要自定义单元格了

image.png 只读模式

image.png

image.png

编辑模式下

其实文档里写的很清楚,只读模式的时候用render去设置单元格,编辑模式下用renderformitem去设置单元格。最开始我没搞懂这点才像个没头苍蝇一样乱转。 image.png 知道这两个api的作用后,代码就很简单了,在renderformitem的时候去调用自定义的组件,render只读下遍历,给每个采集值加上边框:

 {
      title: '记录',
      dataIndex: 'collectValue',
      key: 'collectValue',
      width: '25%',
      align: 'center',
      renderFormItem: (a) => {
        //@ts-ignore
        if (a?.entity?.type == '1') {
          //@ts-ignore
          return <InputList count={a?.entity?.sampleCount || 0} />;
        } else {
          return <TextArea />;
        }
      },
      render: (value, record) => {
        //数值
        if (record.type == '1') {
          const arr = record?.collectValue?.toString().split(',') || [];
          return (
            <>
              <Row gutter={[4, 4]}>
                {arr.map((item: string, index: number) => {
                  return (
                    <>
                      <Col span={6}>
                        <div
                          key={+new Date() + index}
                          style={{ border: '1px solid rgb(217,217,217)', padding: 2 }}
                        >
                          {item}
                        </div>
                      </Col>
                    </>
                  );
                })}
              </Row>
            </>
          );
        } else {
          return !value || value == '-' ? '' : value;
        }
      },
    },
    
    
    //自定义的InputList
    import { Col, Input, Row } from 'antd';

type InputListPropsType = {
  count: number;
  value?: string;
  onChange?: (value: string) => void;
};
const InputList: React.FC<InputListPropsType> = (props) => {
  const { count, value = '', onChange = () => {} } = props;
  const numArr = value?.toString().split(',') || [];
  const showArr: (string | number)[] = [];
  for (let i = 0; i < count; i++) {
    if (i < numArr.length) {
      showArr.push(numArr[i]);
    } else {
      showArr.push('');
    }
  }

  const onSave = (collectValue: number | string, index: number) => {
    const changeArr: (string | number)[] = [];
    showArr.map((item, i) => {
      if (i === index && collectValue != '') {
        changeArr.push(collectValue);
      } else if (item != '') {
        changeArr.push(item);
      }
    });
    onChange(changeArr.toString());
  };
  return (
    <Row gutter={[4, 4]} style={{ width: '100%' }}>
      {showArr.map((item, index) => {
        return (
          <>
            <Col span={6} key={+new Date() + index}>
              <Input
                style={{ width: '100%' }}
                defaultValue={item}
                onBlur={(e) => {
                  onSave(e.target.value, index);
                }}
              />
            </Col>
          </>
        );
      })}
    </Row>
  );
};

export default InputList;

自定义组件的时候,value和onchange是自动包裹的,不需要手动去传入。 这里有两个问题因为时间比较紧急还没好好去解决: 1、renderFormItem传入的参数的类型定义,总是报错,看源码的定义是这样的 image.png 2、第二点就是遍历的时候key的选择,因为遍历的采集值也只是逗号分割的数字字符串而已,没有给唯一的id表示,用index又总是报错,最后采用了时间戳。

仔细阅读文档才发现文档上那个例子已经写的非常清晰明了了,还是要多读文档。

image.png