【react】react中使用antd的table实现拖拽列宽保存记忆功能

在开发的过程中,根据业务需求,想要实现表格的拖拽,并增加拖动结束后记忆功能,一一激励在开发的过程中遇到的困难点。

根据官网示例实现表格可拖拽,以下是页面代码:

import React from 'react';
import { Resizable } from 'react-resizable';
import { Table } from 'antd';
import styles from "./index.less"

const ResizeableTitle = props => {
  const { onResize, width, ...restProps } = props;

  if (!width) {
    return <th {...restProps} />;
  }

  return (
    <Resizable
      width={width}
      height={0}
      onResize={onResize}
      draggableOpts={{ enableUserSelectHack: false }}
    >
      <th {...restProps} />
    </Resizable>
  );
};

class Demo extends React.Component {
  state = {
    columns: [
      {
        title: 'Date',
        dataIndex: 'date',
        width: 200,
      },
      {
        title: 'Amount',
        dataIndex: 'amount',
        width: 100,
      },
      {
        title: 'Type',
        dataIndex: 'type',
        width: 100,
      },
      {
        title: 'Note',
        dataIndex: 'note',
        width: 100,
      },
      {
        title: 'Action',
        key: 'action',
        render: () => <a>Delete</a>,
      },
    ],
  };

  components = {
    header: {
      cell: ResizeableTitle,
    },
  };

  data = [
    {
      key: 0,
      date: '2018-02-11',
      amount: 120,
      type: 'income',
      note: 'transfer',
    },
    {
      key: 1,
      date: '2018-03-11',
      amount: 243,
      type: 'income',
      note: 'transfer',
    },
    {
      key: 2,
      date: '2018-04-11',
      amount: 98,
      type: 'income',
      note: 'transfer',
    },
  ];

  handleResize = index => (e, { size }) => {
    this.setState(({ columns }) => {
      const nextColumns = [...columns];
      nextColumns[index] = {
        ...nextColumns[index],
        width: size.width,
      };
      return { columns: nextColumns };
    });
  };

  render() {
    const columns = this.state.columns.map((col, index) => ({
      ...col,
      onHeaderCell: column => ({
        width: column.width,
        onResize: this.handleResize(index)
      }),
    }));

    return (<div className={styles.resizableClass}>
      <Table bordered components={this.components} columns={columns} dataSource={this.data} />;
      </div>)
  }
}

export default Demo;

以下为index.less的代码

.resizableClass{
  :global{
    .react-resizable {
        position: relative;
        background-clip: padding-box;
      }
      
    .react-resizable-handle {
        position: absolute;
        width: 10px;
        height: 100%;
        bottom: 0;
        right: -5px;
        cursor: col-resize;
        z-index: 1;
      }
      .ant-table-small > .ant-table-content > .ant-table-scroll > .ant-table-header > table > .ant-table-thead > tr > th{
        border-left: 1px solid #f1f1f1;
      }
  }
}

 下一步便是获取鼠标拖拽结束时的列宽,首先在ResizeableTitle中给Resizable添加onResizeStop事件,如以下代码:

const ResizeableTitle = props => {
  const { onResize, width, ...restProps } = props;

  if (!width) {
    return <th {...restProps} />;
  }

  const handleResizeStop = (e) => {
    console.log("e===",e)
  }

  return (
    <Resizable
      width={width}
      height={0}
      onResize={onResize}
      onResizeStop={handleResizeStop}
      draggableOpts={{ enableUserSelectHack: false }}
    >
      <th {...restProps} />
    </Resizable>
  );
};

打印出来的 e 并没有我们想要的dataIndex和width,后面发现在调用时的onHeaderCell里column就是变更后的列,它将column.width作为width传递给了ResizeableTitle,同理,我们可将column传递过去,仅仅拿到改变后的列是不够的,我们还需要传递原有的state.columns

const columns = this.state.columns.map((col, index) => ({
      ...col,
      onHeaderCell: column => ({
        width: column.width,
        onResize: this.handleResize(index),
        column:column,// 将 变更列的列表 传递给 ResizeableTitle
        columns: this.state.columns // 将 state.columns 传递给 ResizeableTitle
      }),
    }));

这样我们便能在ResizeableTitle拿到值,将其放在handleResizeStop中进行数据处理。在这里突然发现,this.state.columns也是被改变了的,如此我们就只需要穿this.state.columns了,column不用传,但是由于我们项目是用的接口存储,再加上还有控制列的显示与隐藏,因此需要进行传递。但本次示例主要是想存在localStorage。给state.columns每一项加上key,保证唯一性。

const { columns } = props;
const handleResizeStop = (e) => {
    let pageColumns = []
    columns.forEach(ele =>{
      pageColumns.push({key:ele.key, width:ele.width})
    })
    window.localStorage.setItem('pageColumns',JSON.stringify(pageColumns))
  }

鼠标拖拽后,我们在控制台可以看到以下数据,这里我给操作列也加上了width。 

接下来我们就可以在Dom的componentDidMount中进行处理了,这样就可以实现数据存储功能啦。

 componentDidMount() {
    const { columns } = this.state;
    const popoverColumns = []
    let localColumns = window.localStorage.getItem('pageColumns')
    if(localColumns){
      const cols = JSON.parse(localColumns)
      cols.forEach(ele=>{
        if (columns.filter(item => ele.key === item.key)[0]) {// 查找有没有相同列
          if(ele.width){
            popoverColumns.push(Object.assign(columns.filter(item => item.key === ele.key)[0], { width: ele.width}))
          }else{
            popoverColumns.push(Object.assign(columns.filter(item => item.key === ele.key)[0]))
          }
        }
      })
    }
    this.setState({ columns:popoverColumns})
  }

以下是完整代码 (index.less一直没变还是用的上面的代码)

import React from 'react';
import { Resizable } from 'react-resizable';
import { Table } from 'antd';
import styles from "./index.less"

const ResizeableTitle = props => {
  const { onResize, width,column,columns, ...restProps } = props;

  if (!width) {
    return <th {...restProps} />;
  }

  const handleResizeStop = (e) => {
    let pageColumns = []
    columns.forEach(ele =>{
      pageColumns.push({key:ele.key, width:ele.width})
    })
    window.localStorage.setItem('pageColumns',JSON.stringify(pageColumns))
  }

  return (
    <Resizable
      width={width}
      height={0}
      onResize={onResize}
      onResizeStop={handleResizeStop}
      draggableOpts={{ enableUserSelectHack: false }}
    >
      <th {...restProps} />
    </Resizable>
  );
};

class Demo extends React.Component {
  state = {
    columns: [
      {
        title: 'Date',
        dataIndex: 'date',
        key: 'date',
        width: 200,
      },
      {
        title: 'Amount',
        dataIndex: 'amount',
        key: 'amount',
        width: 100,
      },
      {
        title: 'Type',
        dataIndex: 'type',
        key: 'type',
        width: 100,
      },
      {
        title: 'Note',
        dataIndex: 'note',
        key: 'note',
        width: 100,
      },
      {
        title: 'Action',
        key: 'action',
        width: 100,
        render: () => <a>Delete</a>,
      },
    ],
    listColumns:[]
  };

  componentDidMount() {
    const { columns } = this.state;
    const popoverColumns = []
    let localColumns = window.localStorage.getItem('pageColumns')
    if(localColumns){
      const cols = JSON.parse(localColumns)
      cols.forEach(ele=>{
        if (columns.filter(item => ele.key === item.key)[0]) {// 查找有没有相同列
          if(ele.width){
            popoverColumns.push(Object.assign(columns.filter(item => item.key === ele.key)[0], { width: ele.width}))
          }else{
            popoverColumns.push(Object.assign(columns.filter(item => item.key === ele.key)[0]))
          }
        }
      })
    }
    this.setState({ columns:popoverColumns})
  }

  components = {
    header: {
      cell: ResizeableTitle,
    },
  };

  data = [
    {
      key: 0,
      date: '2018-02-11',
      amount: 120,
      type: 'income',
      note: 'transfer',
    },
    {
      key: 1,
      date: '2018-03-11',
      amount: 243,
      type: 'income',
      note: 'transfer',
    },
    {
      key: 2,
      date: '2018-04-11',
      amount: 98,
      type: 'income',
      note: 'transfer',
    },
  ];

  handleResize = index => (e, { size }) => {
    this.setState(({ columns }) => {
      const nextColumns = [...columns];
      nextColumns[index] = {
        ...nextColumns[index],
        width: size.width,
      };
      return { columns: nextColumns };
    });
  };

  render() {
    const columns = this.state.columns.map((col, index) => ({
      ...col,
      onHeaderCell: column => ({
        width: column.width,
        onResize: this.handleResize(index),
        column:column,// 将 变更列的列表 传递给 ResizeableTitle
        columns: this.state.columns // 将 state.columns 传递给 ResizeableTitle
      }),
    }));

    return (<div className={styles.resizableClass}>
      <Table bordered components={this.components} columns={columns} dataSource={this.data} />;
      </div>)
  }
}

export default Demo;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值