博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
基于H5实现的react拖拽排序组件
阅读量:7045 次
发布时间:2019-06-28

本文共 3926 字,大约阅读时间需要 13 分钟。

拖拽排序组件Github地址:

因为使用了react.js技术栈,所以封装优先考虑输入和输出。基于数据驱动去渲染页面、控制拖拽元素的顺序。

由于我不考虑兼容IE8等旧版本浏览器,拖拽的效果采用了HTML5的拖放(Drag 和 drop)。当然,如果要求兼容性丰富,使用鼠标点击的相关事件也很简单。

实现的效果如下:

图片描述

第一步是先了解H5拖放的相关属性,MDN上有详细的说明,链接为

有一点需要注意的是,react.js会给所有的属性事件名称前加上"on",后面则为驼峰式写法。例如原生的click事件,在react.js里应使用onClick事件。

我的组件使用的拖放属性如下:

  1. draggable 当设置为true时,当前控件可以拖拽
  2. onDragStart 控件开始被拖拽时触发的事件,它提供一个dataTransfer.setData()方法,将必要的数据存储在对象中便于在其它方法中调用
  3. onDragOver 规定当前控件可以接收拖拽的组件的方法,一般在此方法中阻止冒泡
  4. onDragEnter 拖动后鼠标进入另一个可接受区域时触发,通过它可以实现移入效果
  5. onDragLeave a拖到b,离开b的时候触发,可以用于监听消除移入效果的时机
  6. onDrop 当控件被“释放”到一个有效的释放目标位置时触发,我在这个方法中处理数据,并通过它调用onChange方法,将value值暴露给父组件

其中draggable,onDragStart是被“拖拽”方需要设置的属性,onDragOver,onDragEnter,onDragLeave和onDrop是被“拖入”方需要设置的属性。不过对于我的拖拽排序组件,每一个元素都是拖拽和拖入方

第二步,既然“她"是react.js的组件, 按照习惯,简单的将输入属性定为为value,同时,暴露onChange事件监听value的变化,并将其暴露给父组件,同时,暴露一个属性sortKey告诉组件使用哪个key作为排序字段。

既然涉及到排序,同时允许指定组件每个元素的内部子组件,我将输入数据格式定义为一个数组对象,其中content可以为reactNode:

value: [                {                    content: 'div1',                    code: '01',                    sort: 0,                },                {                    content: 'div2',                    code: '02',                    sort: 1                },                {                    content: 'div3',                    code: '03',                    sort: 2                },                {                    content: 'div5',                    code: '05',                    sort: 5                },                {                    content: 'div4',                    code: '04',                    sort: 4                }]

根据value我去生成可排序组件的每个node,关键代码如下:

// 生成拖拽组件    createDraggleComponent(data, sortKey, style, uId) {        return data.sort(this.compare(sortKey)).map((item) => {            return (                
{item.content}
) }) } render() { const { value, sortKey, style } = this.props; return (
{this.createDraggleComponent(value, sortKey, style)}
) }

其中的属性方法具体实现:

// 拖动事件    domdrugstart(sort, code, ee) {        ee.dataTransfer.setData("code", code);        ee.dataTransfer.setData("sort", sort);    }    // 拖动后鼠标进入另一个可接受区域    dragenter(ee) {        ee.target.style.border = '2px dashed #008dff';        ee.target.style.boxShadow = '0 0 8px rgba(30, 144, 255, 0.8)';    }    // a拖到b,离开b的时候触发    dragleave(ee) {        ee.target.style.border = '1px solid grey';        ee.target.style.boxShadow = '';    }    // 对象排序    compare(key) {        return (obj1, obj2) => {            if (obj1[key] < obj2[key]) {                return -1;            } else if (obj1[key] > obj2[key]) {                return 1;            }            return 0        }    }    // 当一个元素或是选中的文字被拖拽释放到一个有效的释放目标位置时    drop(dropedSort, data, sortKey, ee) {        ee.preventDefault();        const code = ee.dataTransfer.getData("code");        const sort = ee.dataTransfer.getData("sort");        if (sort < dropedSort) {            data.map(item => {                if (item.code === code) {                    item[sortKey] = dropedSort;                } else if (item[sortKey] > sort && item[sortKey] < dropedSort + 1) {                    item[sortKey]--;                }                return item;            });        } else {            data.map(item => {                if (item.code === code) {                    item[sortKey] = dropedSort;                } else if (item[sortKey] > dropedSort - 1 && item[sortKey] < sort) {                    item[sortKey]++;                }                return item;            });        }        this.props.onChange(data)    }    allowDrop(ee) {        ee.preventDefault();    }

值得注意的点其实只有一个,我控制顺序的时候,并没有使用.target.before(document.getElementById({id}))去实际操控节点,而是在每次触发onDrop时间的时候,处理数据的sort,并通过onChange事件暴露给父组件,将数据输出,通过改变value值触发虚拟dom重新去渲染,以此控制顺序。

根据公司的要求,在此基础上,我还实现了拖拽复制的功能,这个等下次自己不懒的时候再记录下来。

转载地址:http://wxhal.baihongyu.com/

你可能感兴趣的文章
React小技巧: 使用Context跨组件树传递数据
查看>>
Objective-C设计模式解析-迭代器
查看>>
keepalived搭建zabbix server双机高可用
查看>>
怎样使用和设置.babelrc
查看>>
我的世界:一个村落(其二)
查看>>
Longest Increasing Path in a Matrix
查看>>
直击微信公开课:2019年小程序将会有哪些改变?
查看>>
一个沉重的问题:软件开发到底还有价值吗?
查看>>
13岁女孩因发布JavaScript无限循环代码被捕
查看>>
Yelp开源数据管道项目最新组件——数据管道客户端库
查看>>
Coinbase是如何在其加密货币交易平台上应对扩展性挑战的
查看>>
Elixir:可能成为下一代Web开发语言
查看>>
苹果Q1财报出炉:手机收入下滑15%,服务收入增长19%
查看>>
Racket 6.7最新版本:提供对Android App的支持及改进的REPL等等
查看>>
Eclipse发布MicroProfile 1.4和2.0
查看>>
Kubernetes日志分析利器:Elassandra部署使用指南
查看>>
TOP 13大最热开源微服务Java框架
查看>>
Swift 3来了!
查看>>
京东构建了全球最大的Kubernetes集群,没有之一
查看>>
Node项目之需求收集平台(一)- 基本介绍
查看>>