前言
作为开发者,我们总是会不经意间的遇到一些令人头疼的需求。比如五彩斑斓的黑,根据手机壳变换APP的颜色等等,你说怎么办。虽然在一般情况下不会这么棘手,但是有些需求刚拿到的时候还是会一筹莫展。
表格间数据传递
曾经遇到一个类似这样的需求:A表的数据需要沿用B表中的数据,而且要尽量少的步骤。具体什么意思呢,意思就是完成一个类似于下面这种效果:
这个该这么搞,直接给产品说,对不起实现不了。
可是产品却告诉我,不行不行,必须实现。
没办法,只好妥协。
梳理
OK,我们来理理思路,首先确定一下现有的主要开发环境:
- 框架:react
- UI库:antd
既然要实现上图所示的拖放效果,那么HTML5的拖放一系列API(Drag 和 Drop等)肯定就是主角了。原生API以及用法可以点击这里进行摸索。
熟悉了API后我们便要对需求进行分析,明确三个要点:第一是拖放的动作,这个用拖放API就能很好的解决;第二是表格间的数据交互,也就是怎么把表格B中部分数据(序号)添加到表格A(沿用信息);第三是表格B中每一行的序号与表格A中的沿用信息都是一对多的关系,而且表格A中的沿用信息是即可添加也可以替换的。
弄清楚需要解决的要点后,我们就可以着手coding了。
具体实现
首先,我们要先建立两张表格,并且制造假数据:
import React, { Component } from 'react';
import {Table, Row, Col, Button} from 'antd';
export class App extends Component {
columnsA
columnsB
constructor(props) {
super(props);
this.columnA = [
{
title: '姓名',
dataIndex: 'name',
key: 'name',
},
{
width: 100,
title: '沿用信息',
dataIndex: 'obj',
key: 'obj',
}
]
this.columnsB = [
{
title: '序号',
dataIndex: 'num',
key: 'num',
},
{
title: '信息',
dataIndex: 'info',
key: 'info',
}
]
this.state = {
dataSourceA: [
{
key: '1',
name: '小明',
obj: ''
},
{
key: '2',
name: '李华',
obj: ''
},
{
key: '3',
name: '小花',
obj: ''
}
],
dataSourceB: [
{
key: '1',
num: '1',
info: '信息一'
},
{
key: '2',
num: '2',
info: '信息一'
},
{
key: '3',
num: '3',
info: '信息一'
}
]
}
}
componentDidMount(){
}
render(){
return (
<div className="content" style={{margin: "20px 20px"}}>
<Row gutter={24}>
<Col span={11}>
<Table columns={this.columnsA} dataSource={this.state.dataSourceA} />
</Col>
<Col span={11}>
<Table columns={this.columnsB} dataSource={this.state.dataSourceB} />
</Col>
</Row>
</div>
)
}
}
效果如下:
接下来就是实现拖放动作,因为这里使用了antd的Table组件,所以我们很自然的就可以想到在columns做文章,在这里把原生的拖放API进行拓展。序号是需要拖拽的元素,而沿用信息是需要进行接收的元素。为了让拖放更加明显,所以我们在这里也加了一点样式:
this.columnA = [
{
title: '姓名',
dataIndex: 'name',
key: 'name',
},
{
width: 100,
title: '沿用信息',
dataIndex: 'obj',
key: 'obj',
render: (value, row, index) => {
return <div
id={'drop'+index}
style={{height:"30px",width:"30px",border:"1px solid #eee",textAlign: "center",lineHeight: "30px"}}
onDrop={(e) => {
e.preventDefault();
this.drop(e)
}}
onDragOver={this.allowDrop}
>{value}</div>
}
}
]
this.columnsB = [
{
title: '序号',
dataIndex: 'num',
key: 'num',
render: (value, row, index) => {
return <div
draggable="true"
id={'drag'+value}
style={{height:"30px",width:"30px",border:"1px solid #eee",textAlign: "center",lineHeight: "30px"}}
onDragStart={(e) => {
this.drag(e)
}}>{value}</div>
}
},
{
title: '信息',
dataIndex: 'info',
key: 'info',
}
]
drag = (e) => {
console.log(e)
};
drop = (e) => {
console.log(e);
};
allowDrop = (e) => {
e.preventDefault();
};
效果如下:
拖放动作是有了,但是两个表格的数据并没有发生变化,所以接下来我们要进行数据的处理。想要进行数据的传递,我们可以利用拖放API中的:
- dataTransfer.setData()方法设置被拖数据的数据类型和值;
- dataTransfer.getData()方法获得被拖的数据。该方法将返回在 setData() 方法中设置为相同类型的任何数据。
// columnsA
{
width: 100,
title: '沿用信息',
dataIndex: 'obj',
key: 'obj',
render: (value, row, index) => {
return <div
id={'drop'+index}
style={{height:"30px",width:"30px",border:"1px solid #eee",textAlign: "center",lineHeight: "30px"}}
onDrop={(e) => {
e.preventDefault();
this.drop(e)
}}
onDragOver={this.allowDrop}
>{value}</div>
}
}
// columnsB
{
title: '序号',
dataIndex: 'num',
key: 'num',
render: (value, row, index) => {
return <div
draggable="true"
id={'drag'+value}
style={{height:"30px",width:"30px",border:"1px solid #eee",textAlign: "center",lineHeight: "30px"}}
onDragStart={(e) => {
this.drag(e,value)
}}>{value}</div>
}
},
drag = (e,value) => {
console.log(e)
e.dataTransfer.setData('value', value)
};
drop = (e, key) => {
let value = e.dataTransfer.getData('value')
console.log("获取数据:",value);
};
可以看到,我们已经能够获取到拖拽的数据了。最后我们要对表格A的数据进行处理,首先对dataSourceA进行遍历,如果其中的元素的key和接受数据的元素的key相等的话,那就对此元素的obj字段进行赋值:
// columnsA
{
width: 100,
title: '沿用信息',
dataIndex: 'obj',
key: 'obj',
render: (value, row, index) => {
return <div
id={'drop'+index}
style={{height:"30px",width:"30px",border:"1px solid #eee",textAlign: "center",lineHeight: "30px"}}
onDrop={(e) => {
e.preventDefault();
this.drop(e, row.key)
}}
onDragOver={this.allowDrop}
>{value}</div>
}
}
drop = (e, key) => {
let value = e.dataTransfer.getData('value')
console.log("获取数据:",value);
let data = this.state.dataSourceA;
data.forEach((item) => {
if (item.key == key) {
item.obj = value
}
});
this.setState({
dataSourceA: data
})
};
看看效果:
当然我们也可以把表格A中的数据打印出来看看:
数据真实的发生了改变~~
这个demo基本就算完成了,以上代码结合起来差不多就是此次demo的完整代码。
参考
https://www.runoob.com/html/html5-draganddrop.html
https://developer.mozilla.org/zh-CN/docs/Web/API/Document/drag_event
最后
很多时候遇到的问题,看似有点麻烦,但是只要去仔分析,然后对问题进行拆解,总是能找到比较好的解决方案的。
文章若有不足或有更好建议,欢迎提出,大家一起讨论~