借鉴了网上大佬的一些文章,记录实现一个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