hooks手动实现拖拽组件
App.js组件
import React from "react";
import './App.css';
import useDraggable from './useDraggable';
// 数据源
const list = [
{
src: 'https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=3942751454,1089199356&fm=26&gp=0.jpg',
title: '图片1'
},
{
src: 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1604224186531&di=528125c9c6c2ab7f5dd0f4f108704408&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fblog%2F201306%2F26%2F20130626161523_zw25t.jpeg',
title: '图片2'
},
{
src: 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1604224186529&di=31915ae6ab56c476bd2308e1e320c76f&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201301%2F20%2F20130120171927_KaevQ.jpeg',
title: '图片3'
}
];
//处理样式
function cls(def, ...conditions) {
const list = [def];
conditions.forEach(cond => {
if (cond[0]) {
list.push(cond[1]);
}
})
console.log(list);
return list.join(' ')
}
// 默认导出组件
export default function App() {
return (
<div className='App'>
<DraggableList list={list} />
</div>
)
}
function DraggableList({ list }) {
const { dragList, createDropperProps, createDraggerProps } = useDraggable(list);
console.log(dragList);
return dragList.map((item, i) => {
if (item.type === 'BAR') {
return <Bar id={i} {...createDropperProps(i)} key={item.id} />
} else {
return <Draggable {...createDraggerProps(i,item.id)}>
<Card {...item.data} />
</Draggable>
}
})
}
function Draggable({ children, eventHandlers, dragging, id }) {
console.log('dragging===id',dragging===id);
return <div {...eventHandlers} draggable={true}
className={cls('draggable',[dragging===id,'dragging'])}>
{children}
</div>
}
function Bar({id,dragging,dragOver,eventHandlers}) {
if(id===dragging+1){
return null;
}
return <div {...eventHandlers} className={cls('draggable-bar',[dragOver===id,'dragOver'])}>
<div className='inner' style={{height:id===dragOver?'80px':'0px'}} />
</div>
}
function Card({ src, title }) {
return (
<div className='card'>
<img src={src} />
<span>{title}</span>
</div>
)
}
useDraggable.js 状态文件
import React, { useState } from 'react'
const DRAGGABLE = 'DRAGGABLE';
const BAR = 'BAR';
function draggable(item, id) {
return {
type: DRAGGABLE,
id,
data: item
}
}
// 处理元素
function insertBars(list) {
let i = 0
const newBar = () => {
return {
type: BAR,
id: i++
}
}
const newData = [newBar()].concat(
...list.map(item => {
return [draggable(item, i++), newBar()]
})
)
return [newBar()].concat( // 返回元素
...list.map(item => {
return [draggable(item, i++), newBar()]
})
)
}
function clacChanging(list, drag, drop) {
list = list.slice();
const dragItem = list[drag];
// dir>0 从下往上 <0 从上往下
const dir = drag > drop ? -2 : 2;
// drop的地方是bar
const end = dir > 0 ? drop - 1 : drop + 1;
for (let i = drag; i != end; i += dir) {
list[i] = list[i + dir];
}
list[end] = dragItem;
return list;
}
export default function useDraggable(list) {
const [dragList, setDragList] = useState(() => {
return insertBars(list)
})
const [dragOver, setDragOver] = useState(null);
const [dragging, setDragging] = useState(null);
return {
dragList,
createDropperProps: id => {
return {
dragging,
dragOver,
eventHandlers: {
onDragOver: (e) => { // 拖拽元素在目标元素上移动的时候触发的事件,此事件作用在目标元素上
e.preventDefault()
setDragOver(id)
},
onDragLeave: e => {
e.preventDefault()
setDragOver(null)
},
onDrop: e => { // 被拖拽的元素在目标元素上同时鼠标放开触发的事件,此事件作用在目标元素上
e.preventDefault()
setDragOver(null)
setDragList(list => {
return clacChanging(list, dragging, id)
})
}
}
}
},
createDraggerProps: (id,key) => {
return {
id,
key: id,
dragging,
eventHandlers: {
onDragStart: () => { // 当拖拽元素开始被拖拽的时候触发的事件,此事件作用在被拖曳元素上
setDragging(id);
},
onDragEnd: () => { // 当拖拽完成后触发的事件,此事件作用在被拖曳元素上
setDragging(null);
}
}
}
}
}
}
App.css 样式文件
.App{
font-family: sans-serif;
text-align: center;
}
.card{
display: flex;
align-items: center;
padding: 10px;
box-shadow: grey 1px 2px 3px;
cursor: pointer;
user-select: none;
}
.card img{
border-radius: 36px;
width: 72px;
height: 72px;
}
.card span{
margin-left: 20px;
}
.draggable-bar{
padding:10px 0;
}
.draggable{
background: white;
transition: all 0.3s ease;
}
.draggable.dragging{
opacity: 0;
position: fixed;
width: 100%;
}
.draggable-bar{
transition:background-color 1s ease-out;
padding: 10px;
}
.draggable-bar .inner{
}
.draggable-bar.dragOver .inner{
transition: height 0.3s ease;
margin: 10px 0;
background-color: red;
}