返回顶部
首页 > 资讯 > 精选 >怎么实现react拖拽hooks
  • 707
分享到

怎么实现react拖拽hooks

2023-06-14 07:06:45 707人浏览 泡泡鱼
摘要

这篇文章主要介绍了怎么实现React拖拽hooks,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。前言源码总共也就一百多行,看完这个大致可以理解一些成熟的react拖拽库的实现

这篇文章主要介绍了怎么实现React拖拽hooks,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

前言

源码总共也就一百多行,看完这个大致可以理解一些成熟的react拖拽库的实现思路,比如react-dnd,然后你上手这些库的时候就非常快了。

使用hooks实现的大致效果动图如下:

怎么实现react拖拽hooks

我们的目标是实现一个useDrag和useDrop的hooks,类似以下用法就可以轻松让元素可以拖拽,并且在拖拽的各个生命周期,如下,可以自定义传递消息(顺便介绍几个拖拽会触发的事件)。

  • dragstart:用户开始拖拉时,在被拖拉的节点上触发,该事件的target属性是被拖拉的节点。

  • dragenter:拖拉进入当前节点时,在当前节点上触发一次,该事件的target属性是当前节点。通常应该在这个事件的监听函数中,指定是否允许在当前节点放下(drop)拖拉的数据。如果当前节点没有该事件的监听函数,或者监听函数不执行任何操作,就意味着不允许在当前节点放下数据。在视觉上显示拖拉进入当前节点,也是在这个事件的监听函数中设置。

  • draGover:拖拉到当前节点上方时,在当前节点上持续触发(相隔几百毫秒),该事件的target属性是当前节点。该事件与dragenter事件的区别是,dragenter事件在进入该节点时触发,然后只要没有离开这个节点,dragover事件会持续触发。

  • dragleave:拖拉操作离开当前节点范围时,在当前节点上触发,该事件的target属性是当前节点。如果要在视觉上显示拖拉离开操作当前节点,就在这个事件的监听函数中设置。

使用方法 + 源码讲解

class Hello extends React.Component<any, any> { constructor(props: any) {  super(props)  this.state = {} } render() {  return (   <DragAndDrop>    <DragElement />    <DropElement />   </DragAndDrop>  ) }}ReactDOM.render(<Hello />, window.document.getElementById("root"))

如上,DragAndDrop组件的作用是给所有的使用useDrag和useDrop的组件传递消息,比如当前拖拽的元素是那个dom,或者你想要其他信息都可以往里面加,我们看看它的实现。

const DragAndDropContext = React.createContext({ DragAndDropManager: {} });const DragAndDrop = ({ children }) => ( <DragAndDropContext.Provider value={{ DragAndDropManager: new DragAndDropManager() }}>  {children} </DragAndDropContext.Provider>)

可以看到传递消息是用react的Context的api去实现的,重点就是这个DragAndDropManager,我们看下实现

export default class DragAndDropManager { constructor() {  this.active = null  this.subscriptions = []  this.id = -1 } setActive(activeProps) {  this.active = activeProps  this.subscriptions.forEach((subscription) => subscription.callback()) } subscribe(callback) {  this.id += 1  this.subscriptions.push({   callback,   id: this.id,  })  return this.id } unsubscribe(id) {  this.subscriptions = this.subscriptions.filter((sub) => sub.id !== id) }}

setActive的作用是用来记录当前drag的元素是哪个,useDrag里面会用到,我们在看useDrag的hooks实现的时候就会明白只要调用setActive方法把drag的dom元素传进去,是不是就知道当前拖拽的元素是哪个了呢。

除此之外,我还增加了订阅事件的api,subscribe,目前我并没有使用它,本次示例里你可以忽略这部分,知道可以添加订阅事件就行。

接着我们看看,useDrag的使用,DragElement的实现如下:

function DragElement() { const input = useRef(null) const hanleDrag = useDrag({  ref: input,  collection: {}, // 这里可以填写任意你想传递给drop元素的消息,后面会通过参数的形式传递给drop元素 }) return (  <div ref={input}>   <h2 role="button" onClick={hanleDrag}>    drag元素   </h2>  </div> )}

我们就来看下useDrag的实现,非常简单

export default function useDrag(props) { const { DragAndDropManager } = useContext(DragAndDropContext)  const handleDragStart = (e) => {  DragAndDropManager.setActive(props.collection)  if (e.dataTransfer !== undefined) {   e.dataTransfer.effectAllowed = "move"   e.dataTransfer.dropEffect = "move"   e.dataTransfer.setData("text/plain", "drag") // firefox fix  }  if (props.onDragStart) {   props.onDragStart(DragAndDropManager.active)  } }  useEffect(() => {  if (!props.ref) return () => {}  const {   ref: { current },  } = props  if (current) {   current.setAttribute("draggable", true)   current.addEventListener("dragstart", handleDragStart)  }  return () => {   current.removeEventListener("dragstart", handleDragStart)  } }, [props.ref.current]) return handleDragStart}

useDrag做的事情非常简单,

  • 首先通过useContext,来把获取最外层store的数据,也就是上面代码的DragAndDropManager

  • 在useEffect里面,如果外界传入了ref,就将这个dom元素的属性draggable设为true,也就是可拖拽状态

  • 然后给这个元素绑定dragstart事件,注意了,销毁组件的时候我们要移除事件,以防内存泄漏

  • handleDragStart事件首先把外界传的props.collection更新到我们的外界仓库里,这样每一个要drag,也就是拖拽的元素都可以将我们useDrag中传是入的useDrag({collection: {}})信息,通过DragAndDropManager.setActive(props.collection)的方式,传入到外界的store

  • 接着我们dataTransder属性上做一些事,目的是设置元素的拖拽属性为move,并且为了兼容firefox做了处理。

  • 最后每当出发drag事件的时候,外界传入的onDragStart事件也会触发,并且我们将store里的数据传入进去

其中,useDrop的使用,DropElement的实现如下:

function DropElement(props: any): any { const input = useRef(null) useDrop({  ref: input,  // e代表dragOver事件发生时,正在被over的元素的event对象  // collection是store存储的数据  // showAfter是表示,是否鼠标拖拽元素时,鼠标经过drop元素的上方(上方就是上半边,下方就是下半边)  onDragOver: (e, collection, showAfter) => {  // 如果经过上半边,drop元素的上边框就是红色   if (!showAfter) {    input.current.style = "border-bottom: none;border-top: 1px solid red"   } else {    // 如果经过下半边,drop元素的上边框就是红色    input.current.style = "border-top: none;border-bottom: 1px solid red"   }  },  // 如果在drop元素上放开鼠标,则样式清空  onDrop: () => {   input.current.style = ""  },  // 如果在离开drop元素,则样式清空  onDragLeave: () => {   input.current.style = ""  }, }) return (  <div>   <h2 ref={input}>drop元素</h2>  </div> )}

最后,我们来看看useDrop的实现

export default function useDrop(props) {// 获取最外层store里的数据 const { DragAndDropManager } = useContext(DragAndDropContext) const handleDragOver = (e) => { // e就是拖拽的event对象  e.preventDefault()  // getBoundinGClientRect的图请看下面  const overElementHeight = e.currentTarget.getBoundingClientRect().height / 2  const overElementTopOffset = e.currentTarget.getBoundingClientRect().top  // clientY就是鼠标到浏览器页面可视区域的最顶端的距离  const mousePositionY = e.clientY  // mousePositionY - overElementTopOffset就是鼠标在元素内部到元素border-top的距离  const showAfter = mousePositionY - overElementTopOffset > overElementHeight  if (props.onDragOver) {   props.onDragOver(e, DragAndDropManager.active, showAfter)  } } // drop事件 const handledDop = (e: React.DragEvent) => {  e.preventDefault()  if (props.onDrop) {   props.onDrop(DragAndDropManager.active)  } } // dragLeave事件 const handledragLeave = (e: React.DragEvent) => {  e.preventDefault()  if (props.onDragLeave) {   props.onDragLeave(DragAndDropManager.active)  } }  // 注册事件,注意销毁组件时要注销事件,避免内存泄露 useEffect(() => {  if (!props.ref) return () => {}  const {   ref: { current },  } = props  if (current) {   current.addEventListener("dragover", handleDragOver)   current.addEventListener("drop", handledDop)   current.addEventListener("dragleave", handledragLeave)  }  return () => {   current.removeEventListener("dragover", handleDragOver)   current.removeEventListener("drop", handledDop)   current.removeEventListener("dragleave", handledragLeave)  } }, [props.ref.current])}

getBoundingClientRect的api图解:

rectObject = object.getBoundingClientRect();

rectObject.top:元素上边到视窗上边的距离;

rectObject.right:元素右边到视窗左边的距离;

rectObject.bottom:元素下边到视窗上边的距离;

rectObject.left:元素左边到视窗左边的距离;

怎么实现react拖拽hooks

感谢你能够认真阅读完这篇文章,希望小编分享的“怎么实现react拖拽hooks”这篇文章对大家有帮助,同时也希望大家多多支持编程网,关注编程网精选频道,更多相关知识等着你来学习!

--结束END--

本文标题: 怎么实现react拖拽hooks

本文链接: https://lsjlt.com/news/268762.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 怎么实现react拖拽hooks
    这篇文章主要介绍了怎么实现react拖拽hooks,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。前言源码总共也就一百多行,看完这个大致可以理解一些成熟的react拖拽库的实现...
    99+
    2023-06-14
  • 一百多行代码实现react拖拽hooks
    前言 源码总共也就一百多行,看完这个大致可以理解一些成熟的react拖拽库的实现思路,比如react-dnd,然后你上手这些库的时候就非常快了。 使用hooks实现的大致效果动图如...
    99+
    2024-04-02
  • react可拖拽进度条怎么实现
    本文小编为大家详细介绍“react可拖拽进度条怎么实现”,内容详细,步骤清晰,细节处理妥当,希望这篇“react可拖拽进度条怎么实现”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。效果import {&n...
    99+
    2023-06-30
  • react-dnd如何实现拖拽
    这篇文章主要介绍了react-dnd如何实现拖拽的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇react-dnd如何实现拖拽文章都会有所收获,下面我们一起来看看吧。 ...
    99+
    2024-04-02
  • react实现拖拽模态框
    前言 实际开发中,模态框展现数据会经常出现.但不幸的是有时功能开发完了,UI同学突然提出需求希望模态框能拖拽.本文使用的模态框由 ant design 3.0 的 Modal 组件封...
    99+
    2024-04-02
  • react实现自定义拖拽hook
    前沿 最近发现公司的产品好几个模块用到了拖拽功能,之前拖拽组件是通过Html5 drag Api 实现的但体验并不是很好,顺便将原来的拖拽组建稍做修改,写一个自定义hook,方便大家...
    99+
    2024-04-02
  • react怎么实现hooks
    这篇文章主要介绍“react怎么实现hooks”,在日常操作中,相信很多人在react怎么实现hooks问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”react怎么实现hoo...
    99+
    2024-04-02
  • React怎么结合Drag API实现拖拽效果
    本篇内容主要讲解“React怎么结合Drag API实现拖拽效果”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“React怎么结合Drag API实现拖拽效果”吧!认识拖拽鼠标...
    99+
    2023-07-05
  • react中实现拖拽排序react-dnd功能
    dnd文档 html 拖拽排序 import React, { useState, useRef } from 'react'; import { cloneDeep } from...
    99+
    2023-02-06
    拖拽排序react-dnd react拖拽排序
  • react实现简单的拖拽功能
    本文实例为大家分享了react实现简单的拖拽功能的具体代码,供大家参考,具体内容如下 src文件夹下新建文件夹demo  然后在创建两个文件js和css demo.js文...
    99+
    2024-04-02
  • react可拖拽进度条的实现
    效果 import { FC, ReactElement, useRef } from "react"; import styled from "styled-componen...
    99+
    2024-04-02
  • react-beautiful-dnd 实现组件拖拽功能
    目录1.安装2.APi3.react-beautiful-dnd demo3.1 demo1 纵向组件拖拽3.2 demo2 水平拖拽3.3 demo3实现一个代办事项的拖拽(纵向 ...
    99+
    2024-04-02
  • react-beautiful-dnd如何实现组件拖拽
    这篇文章将为大家详细讲解有关react-beautiful-dnd如何实现组件拖拽,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。1.安装在已有react项目中 执行以下命令 so easy。# ...
    99+
    2023-06-20
  • React如何使用sortablejs实现拖拽排序
    目录React使用sortablejs实现拖拽排序sortablejs之强大的拖拽库安装基本示例常用配置总结React使用sortablejs实现拖拽排序 1、使用npm装包 $ n...
    99+
    2023-01-16
    React使用sortablejs sortablejs实现拖拽排序 sortablejs拖拽排序
  • 怎么在Html5中实现一个react拖拽排序组件
    今天就跟大家聊聊有关怎么在Html5中实现一个react拖拽排序组件,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。第一步是先了解H5拖放的相关属性,MDN上有详细的说明,链接为htt...
    99+
    2023-06-09
  • HTML5怎么实现拖拽预览
    本篇内容主要讲解“HTML5怎么实现拖拽预览”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“HTML5怎么实现拖拽预览”吧!源码<!DOCTYPE ...
    99+
    2024-04-02
  • vuedraggable怎么实现拖拽功能
    这篇文章主要介绍了vuedraggable怎么实现拖拽功能的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇vuedraggable怎么实现拖拽功能文章都会有所收获,下面我们一起来看看吧。一、下载依赖npm&nbs...
    99+
    2023-06-29
  • Vue.Draggable拖拽功能怎么实现
    这篇文章主要讲解了“Vue.Draggable拖拽功能怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Vue.Draggable拖拽功能怎么实现”吧!使用cmd命令在项目根目录下下载安...
    99+
    2023-07-04
  • React结合Drag API实现拖拽示例详解
    目录认识拖拽被拖拽元素可释放目标生命周期拖拽操作中的数据传输代码实现如何标记当前拖拽的元素?在画布中拖动数据结构总结认识拖拽 鼠标拖拽是一个常见的交互场景,在这个熟悉的过程将会发生...
    99+
    2023-03-06
    React Drag API拖拽 React Drag API
  • 使用react-beautiful-dnd实现列表间拖拽踩坑
    目录为什么选用react-beautiful-dnd 基本使用方法 基本概念使用方法使用过程中遇到的问题 总结 参考资料为什么选用react-beautiful-dnd 相比于re...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作