antd表格结合react-dnd、react-dnd-html5-backend、immutability-helper实现表头拖拽功能

5 篇文章 0 订阅

最近公司打算重构老项目,采用的技术是蚂蚁的umi框架、antd design pro 、react16.8以及dva。重构过程中,遇到了很多坑,解决了也收获了很多,在这里先说一下antd中的表格表头拖拽排序功能。

先去antd官网了解一下table的相关api方法,目前它做了表格内数据的上下拖拽排序,是结合react-dnd、react-dnd-html5-backend、immutability-helper这三个插件来实现的,这三个插件网上都各自有相应的介绍和用法,自己百度哦。

这里我们想横向拖动表头也是借鉴这个方法去实现的,我们需要在表头的onHeaderCell上绑定moveCell函数(拖拽函数)

 onHeaderCell: column => (
        {
          width: column.width,
          onResize: handleResize(index), //表头可伸缩函数
          index:index,
          moveCell: moveCell, //拖拽函数
          column: column,//表头数据
        }
      ), /

在项目中,因为表头还需要有左右滑动增加宽度的功能,所以这里我把这个功能写到了Resizable这个组件中

// 表头编辑配置
const ResizeableTitle = props => {
  const {
    onResize, width, handle = () => {
    }, index, moveCell, column, ...restProps
  } = props;
  const ref = React.useRef();
  const [{ isOver, dropClassName }, drop] = useDrop({
    accept: type,
    collect: monitor => {
      const { index: dragIndex } = monitor.getItem() || {};
      if (dragIndex === index) {
        return {};
      }
      return {
        isOver: monitor.isOver(),
        dropClassName:
          dragIndex < index ? " drop-over-downward" : " drop-over-upward"
      };
    },
    drop: item => {
      // console.log(item)
      moveCell(item.index, index);
    }
  });
  const [, drag] = useDrag({
    item: { type, index },
    collect: monitor => ({
      isDragging: monitor.isDragging()
    })
  });
  drop(drag(ref));
  if (!width) {
    return <th {...restProps} />;
  }
  return (
    <Resizable
      width={width}
      height={0}
      onResize={onResize}
      draggableOpts={{ enableUserSelectHack: false }}
    >
      {//这里是做的特殊区分,有些表头不能拖拽
        column.key == 'eEdit' || column.key == 'taskInfo' || column.key == 'eLock' 
        || column.key == 'material_count' || column.key == 'title' || column.key == 'scoreVOs' 
        || !column.drag_able || column.is_lock ?
        <th
          style={{width:width}}
          {...restProps}
        />
        :
        <th>
          <span ref={ref} {...restProps} style={{ cursor: "pointer !important", width:width }}></span>
        </th>
      } 
    </Resizable>
  );
};

上面的代码中,就将表头拖拽和伸缩功能都ok了,伸缩不用多说,在这里,着重说一下拖拽点的问题,就是ref,因为是将拖拽和伸缩绑定在了一起,为了尽可能地避免两者功能相互干扰,将拖拽点方法了表头的文字上。

然后是moveCell函数,这个和moveRow的函数差不多,不多说

const moveCell = (dragIndex, hoverIndex) => {
    const  _columns  = columns;
    const dragCell = _columns[dragIndex];
    const hoverCell = _columns[hoverIndex];
    let newColumns = update(columns,{$splice:[[dragIndex, 1], [hoverIndex, 0, dragCell]]}); 
    let newHeaders = newColumns.concat(unShowHeaders)
    let j = 0
    let rowData = [];
   
    for (let i = 0; i < newHeaders.length; i++) {
      headers.forEach((header) => {
        if (newHeaders[i].key == header.key) {
          header.order = j;
          j++;
          rowData.push(header)
        }
      })

    }
    props.putRowEdit(rowData, false);
    setColumns(formatRows(newColumns));
  }

剩下的就是使用ResizeableTitle 覆盖table的cell 、DndProvider容器设定以及HTML5Backend的背景

<DndProvider backend={HTML5Backend} >
          <Table
            components={{
              header: {
                cell: ResizeableTitle,
              },
              body: {
                row: DragableBodyRow
              },
            }}
            onRow={(record, index) => {
              return {
                index,
                moveRow: moveRow
              }
            }}
            bordered
            dataSource={dataSource}
            columns={mergedColumns}
            rowClassName={(record, index) => onRowClassName(record, index)}
          />
    </DndProvider>

ok,到这里就能拖拽和伸缩表头了

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
在使用 antd table 和 react-window 实现虚拟列表时,固定列可以通过以下步骤实现: 1. 首先,在 antd table 组件中设置固定列,可以通过 `fixed` 属性来实现,例如: ```jsx <Table dataSource={data} columns={columns} scroll={{ x: '100vw' }} pagination={false} rowKey="id" sticky /> ``` 其中,`sticky` 属性用于开启固定列功能。 2. 然后,在 react-window 中创建两个列表组件:一个用于显示固定列,另一个用于显示非固定列。我们可以使用 `FixedSizeList` 组件来实现固定列列表,使用 `VariableSizeList` 组件来实现非固定列列表。例如: ```jsx // 固定列列表 const FixedColumnList = ({ height, width, columnWidth, rowCount, rowHeight, columns }) => ( <FixedSizeList height={height} width={width} itemCount={rowCount} itemSize={rowHeight} itemData={{ columns }} > {Row({ isScrolling: false })} </FixedSizeList> ); // 非固定列列表 const VariableColumnList = ({ height, width, columnWidth, rowCount, rowHeight, data, columns }) => ( <VariableSizeList height={height} width={width} itemCount={rowCount} itemSize={index => { // 根据行数据计算行高 const row = data[index]; return rowHeight(row); }} itemData={{ data, columns }} > {Row} </VariableSizeList> ); ``` 其中,`Row` 组件用于渲染每一行数据,其实现可以参考 antd table 组件中的 `rowRender` 方法。 3. 最后,将固定列列表和非固定列列表组合在一起,例如: ```jsx <FixedSizeList height={height} width={fixedWidth} itemCount={rowCount} itemSize={rowHeight} itemData={{ columns: fixedColumns, data }} > {Row({ isScrolling })} </FixedSizeList> <VariableSizeList height={height} width={variableWidth} itemCount={rowCount} itemSize={index => { // 根据行数据计算行高 const row = data[index]; return rowHeight(row); }} itemData={{ data, columns: variableColumns }} > {Row} </VariableSizeList> ``` 其中,`fixedWidth` 和 `variableWidth` 分别表示固定列和非固定列的宽度,可以通过计算得出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值