在开发的过程中,根据业务需求,想要实现表格的拖拽,并增加拖动结束后记忆功能,一一激励在开发的过程中遇到的困难点。
根据官网示例实现表格可拖拽,以下是页面代码:
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;