借鉴了网上大佬的一些文章,记录实现一个react的穿梭框的效果
实现拖拽效果的实现我们需要用到关于拖拽的事件,而在html5中刚好就有原生的拖拽api。
拖拽元素事件
dragstart 当一个元素开始被拖拽的时候触发
drag 这个事件在拖拽源触发
dragend 拖拽源在拖拽操作结束将得到dragend事件对象,不管操作成功与否
目标元素触发事件
dragenter 当拖拽中的鼠标第一次进入一个元素时触发
dragover 当拖拽中的鼠标移动经过一个元素时触发
dragleave 当拖拽中的鼠标离开元素时触发
drop 这个事件在拖拽操作结束释放时于释放元素上触发
需要注意:dragover事件下我们需要阻止浏览器的默认行为,让我们拖拽的元素成为可释放的元素。
而在我们拖拽元素的时候需要存储我们拖拽时携带的数据,这时候就用到了dataTransfer,他有两个方法:
一、setData()
1.第一个参数为携带数据的数据种类的字符串,只能填入类 似“text/plain”或“textml”的表示 MIME类型的文字
2.第二个参数为要携带的数据
二、getData()
1、目标元素接受到被拖放的元素后,执行getData()方法从DataTransfer里获取数据
2、getData()方法的参数为setData()方法中指定的数据类型
Demo:
const list = [
{
uid: '1',
text: '序列1'
},
{
uid: '2',
text: '序列2'
},
{
uid: '3',
text: '序列3'
},
{
uid: '4',
text: '序列4'
},
{
uid: '5',
text: '序列5'
},
]
const Drag = () => {
const [rightList, setRightList] = useState(list)
const [leftList, setLeftList] = useState([])
//鼠标华划过接受拖拽元素的事件
const handleDrop = (callBack, e, arrow) => {
const {dataset:{id}}=e.target
const curData = JSON.parse(e.dataTransfer.getData('itemData'))
callBack(prevData => {
const diffData = prevData.filter(item => item.uid !== curData.uid)
// id 不存在是在不同盒子内拖拽 存在则是在本身盒子内拖拽
if(!id) return [...diffData, curData]
// 找到鼠标划过的目标元素的其盒子内的位置
const index=diffData.findIndex(item=>item.uid===id)
//把拖拽元素放置在鼠标划过元素的上方
diffData.splice(index,0,curData)
return diffData
})
//朝左拖拽
if (arrow==='left') {
setRightList(prvData => prvData.filter(item => item.uid !== curData.uid))
}
// 朝右拖拽
else {
setLeftList(prvData => prvData.filter(item => item.uid !== curData.uid))
}
}
// 拖拽元素进入目标元素时触发事件-为目标元素添加拖拽元素进入时的样式效果
const handleDragEnter = e => e.target.classList.add('over')
// 拖拽元素离开目标元素时触发事件-移除目标元素的样式效果
const handleDragLeave = e => e.target.classList.remove('over')
return (
<div>
<div className='left'
onDragOver={(e) => { e.preventDefault() }}
onDrop={(e) => handleDrop(setLeftList, e, 'left')}
>
{
leftList.map(item => (
<div className='item'
draggable
key={item.uid}
data-id={item.uid}
onDragStart={(e) => { e.dataTransfer.setData('itemData', JSON.stringify(item)) }}
>{item.text}</div>
))
}
</div>
<div className='right'
onDragOver={(e) => { e.preventDefault() }}
onDrop={(e) => handleDrop(setRightList, e, 'right')}
onDragEnter={handleDragEnter}
onDragLeave={handleDragLeave}
>
{
rightList.map(item => (
<div className='item'
draggable
key={item.uid}
data-id={item.uid}
onDragStart={(e) => {
e.dataTransfer.setData('itemData', JSON.stringify(item))
}}
>{item.text}</div>
))
}
</div>
</div>
)
}
export default Drag