hooks手动实现拖拽组件

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;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值