在react中使用Dragula实现网页元素拖拽,嵌套拖拽
在开发一个react项目时,需要实现一个拖拽功能,而由于某些原因,react-dnd,react-beautiful-dnd等react拖拽组件无法被使用。于是我将目光放在了js拖拽库上,在实验了众多后,终于被我找到了dragula。它是我目前所见到的最为简单易用的拖拽库。
github链接: https://github.com/bevacqua/dragula/
1.Dragula基本用法
dragula的用法很简单,首先画出两个区域,并且将这两个区域的id分别命名div2,div3
const data2=[{id:'1',name:'green'},{id:'2',name:'blue'},{id:'3',name:'red'}]
const data3=[{id:'1',name:'cat'},{id:'2',name:'dog'},{id:'3',name:'bird'}]
return (
<div className='dragulaPage'>
<div id='div2' className='dragContainers'>
{data2.map((data)=>(
<div key={data.id} className='dragBlock' style={{border:`1px solid ${data.name}`}}>{data.name}</div>
))}
</div>
<div id='div3' className='dragContainers'>
{data3.map((data)=>(
<div key={data.id} style={{border:`1px solid yellow`}}>{data.name}</div>
))}
</div>
</div>
);
接着调用dragula
import dragula from 'dragula';
const dragSet = dragula([document.getElementById('div2'),document.getElementById('div3')], {
direction: 'horizontal',
});
这样,位于div2和div3中的元素就可以互相拖拽了,是不是很简单。
dragula([ ],{ })拥有两个参数,第一个参数是拖拽区域的集合,第二个是拖拽的默认值的对象,比如代码中的direction就是决定拖拽时水平还是垂直排序。
2.几个比较常用的默认值设置
这里的可拖拽区域就是div2和div3
参数 | 作用 |
---|---|
direction | 拖拽排序方向,默认‘vertical’垂直方向,'horizontal’为水平方向 |
revertOnSpill | 拖拽时,若在在可拖拽区域外停止拖拽,物品会去到上一次经过的可拖拽区域。加上revertOnSpill:true 可以让它回到原点 |
removeOnSpill | removeOnSpill:true ,当在可拖拽区域外停止拖拽时,删除该拖拽的物品 |
mirrorContainer | 生产镜像(分身)的位置,默认document.body |
copy | 是否可以复制(拖拽时拖出一个分身而不是本身)。设为true时所有的可拖拽区域的拖拽都变为复制分身。除此还可以接受函数,如: copy: (el, source) => { if (source.id === 'div2' ) { return true; } else {return false; } } 。此处的source是被拖拽物品所在的可拖拽区域,这样,只有div2中的物品会进行复制 |
accepts | 可以接受拖拽物品的可拖拽区域 accepts: (el, target) => { if (target.id === 'div2' ) return false; return true} } 这样,设置后,div2的区域将不接受拖入物品 |
moves | 通过它可以设定可拖拽物品的可拖拽区域moves: (el, container, handle) =>{ return handle.classList.contains('handle'); } 这样设定后,物品只有classname中有handle字段的区域可以被拖拽 |
3.实例化对象的api
const dragSet = dragula([ ], { });
api | 作用 |
---|---|
drake.containers | 可拖拽区域的集合,并且可以添加或删除区域 |
drake.dragging | 任何一个物品被拖拽时变为true(官方的解释,但这个api我个人用起来感觉有问题) |
drake.start(item) | 调用时开始拖拽 |
drake.end() | 调用时结束拖拽 |
drake.cancel(revert) | 调用时结束拖拽取消拖拽 |
drake.remove() | 调用时移除当前被拖拽的元素 |
drake.destroy() | 强制结束正在进行的拖拽动作,并删除所有的可拖动区域 |
drake.on(‘drag’,(…e)=>{ })有两个参数,第一个是想要进行的操作类型,第二个是一个方法体
drake.on( ) | 参数 | 作用 |
---|---|---|
drake.on(‘drag’) | el,source | 拖拽时会一直调用 |
drake.on(‘dragend’) | el | 拖拽时结束时会调用 |
drake.on(‘drop’) | el, target, source, sibling | 放下时调用 |
drake.on(‘cancel’) | el, container, source | 拖拽取消时调用 |
drake.on(‘remove’) | el, container, source | 物品删除时调用 |
drake.on(‘shadow’) | el, container, source | 阴影位置变化时调用 |
drake.on(‘shadow’) | el, container, source | 阴影位置变化时调用 |
drake.on(‘over’) | el, container, source | 移入某个可拖拽区域时调用 |
drake.on(‘out’) | el, container, source | 移出某个可拖拽区域时调用 |
4.样式
使用时需要手动引入dragula提供的样式,不然拖拽的阴影样式会出错
.gu-mirror {
position: fixed !important;
margin: 0 !important;
z-index: 9999 !important;
opacity: 0.8;
-ms-filter: 'progid:DXImageTransform.Microsoft.Alpha(Opacity=80)';
filter: alpha(opacity=80);
pointer-events: none;
width: 90px;
border: 1px solid transparent;
padding: 0px;
text-align: center;
}
.gu-hide {
display: none !important;
}
.gu-unselectable {
-webkit-user-select: none !important;
-moz-user-select: none !important;
-ms-user-select: none !important;
user-select: none !important;
}
.gu-transit {
opacity: 0.2;
-ms-filter: 'progid:DXImageTransform.Microsoft.Alpha(Opacity=20)';
filter: alpha(opacity=20);
}
5.嵌套拖拽
由于dragula的易用性,嵌套拖拽也变的十分简单,以下代码将div1做成了一个可拖拽的区域。接着,将div1中的dropAbleArea1和div2做成了另一组可拖拽的区域。这样一来,div2中的物品就可拖到dropAbleArea1中,dropAbleArea1可在div1中上下拖动排序。
const dragSet2 = dragula([document.getElementById('dropAbleArea1'),document.getElementById('div2')], {
direction: 'horizontal',
});
const dragSet3 = dragula([document.getElementById('div1')], {
moves: (el, container, handle) =>{
return handle.classList.contains('handle');
}
});
const data1=[{id:'dropAbleArea1',name:'dropAbleArea1'},{id:'area2',name:'area2'},{id:'area3',name:'area3'}]
const data2=[{id:'1',name:'green'},{id:'2',name:'blue'},{id:'3',name:'red'}]
return (
<div className='dragulaPage'>
<div id='div1'className='dragContainers'>
{data1.map((data)=>(
<div key={data.id} style={{height:'100px',border:'1px solid',width:'100%',marginTop:'10px'}}>
<div className='handle' style={{height:'30%'}}>++ {data.name}</div>
<div id={data.id} style={{height:'70%',borderTop:'1px solid',width:'100%',display:'flex'}}></div>
</div>
))}
</div>
<div id='div2' className='dragContainers'>
{data2.map((data)=>(
<div key={data.id} className='dragBlock' style={{border:`1px solid ${data.name}`}}>{data.name}</div>
))}
</div>
</div>
)
6.结语
由于dragula是直接对元素进行操作,不涉及任何数据的处理,所以十分的简便丝毫不显臃肿,于此相对的,编程人员需要处理的数据就大大增加,所以涉及大量复杂数据的拖拽不建议使用。最后,文中列出的属性和api是我认为最有可能用到的一些,并不是全部,如果这些无法满足你的要求,不妨再仔细阅读一遍官方文档。