利用HTML5拖放(Drag 和 Drop)实现Table间数据的交互

xmanlin

前言

作为开发者,我们总是会不经意间的遇到一些令人头疼的需求。比如五彩斑斓的黑,根据手机壳变换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中的:

  1. dataTransfer.setData()方法设置被拖数据的数据类型和值;
  2. 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/h...

https://developer.mozilla.org...

最后

很多时候遇到的问题,看似有点麻烦,但是只要去仔分析,然后对问题进行拆解,总是能找到比较好的解决方案的。

文章若有不足或有更好建议,欢迎提出,大家一起讨论~

阅读 1.1k

前端车站的技术分享
公众号—前端车站

公众号—前端车站

1.1k 声望
7 粉丝
0 条评论

公众号—前端车站

1.1k 声望
7 粉丝
宣传栏