使用react-beautiful-dnd实现列表间拖拽踩坑

为什么选用react-beautiful-dnd

相比于react-dnd,react-beautiful-dnd更适用于列表之间拖拽的场景,支持移动端,且较为容易上手。

基本使用方法

基本概念

  • DragDropContext:构建一个可以拖拽的范围
  • onDragStart:拖拽开始回调
  • onDragUpdate:拖拽中的回调
  • onDragEnd:拖拽结束时的回调
  • Droppable - 可以放置拖拽块的区域
  • Draggalbe - 可被拖拽的元素

使用方法

把你想能够拖放的代码放到DragDropContext中

import { DragDropContext } from 'react-beautiful-dnd';

class App extends React.Component {
  onDragStart = () => {
    /*...*/
  };
  onDragUpdate = () => {
    /*...*/
  }
  onDragEnd = () => {
    // the only one that is required
  };

  render() {
    return (
      <DragDropContext
        onDragStart={this.onDragStart}
        onDragUpdate={this.onDragUpdate}
        onDragEnd={this.onDragEnd}
      >
        <div>Hello world</div>
      </DragDropContext>
    );
  }
}

确定可放置区域Dropppable

import { DragDropContext, Droppable } from 'react-beautiful-dnd';

class App extends React.Component {
  // ...
  render() {
    return (
      <DragDropContext
        onDragStart={this.onDragStart}
        onDragUpdate={this.onDragUpdate}
        onDragEnd={this.onDragEnd}
      >
        <Droppable droppableId="droppable-1">
          {(provided, snapshot) => (
            <div
              ref={provided.innerRef}
              style={{ backgroundColor: snapshot.isDraggingOver ? 'blue' : 'grey' }}
              {...provided.droppableProps}
            >
              <h2>I am a droppable!</h2>
              {provided.placeholder}
            </div>
          )}
        </Droppable>
      </DragDropContext>
    );
  }
}
  • 必需的DroppableId(字符串),用于唯一标识应用程序的droppable。不要更改此ID特别是在拖动时
  • provided.placeholder: 占位符(这个占位符是默认的,一般不咋符合需求)
  • snapshot: 当前拖动状态,可以用来在被拖动时改变Droppable的外观

在Dropppable区域使用Draggable包裹拖拽元素

import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';

class App extends React.Component {
  // ...

  render() {
    return (
      <DragDropContext
        onDragStart={this.onDragStart}
        onDragUpdate={this.onDragUpdate}
        onDragEnd={this.onDragEnd}
      >
        <Droppable droppableId="droppable-1">
          {(provided, snapshot) => (
            <div
              ref={provided.innerRef}
              style={{ backgroundColor: snapshot.isDraggingOver ? 'blue' : 'grey' }}
              {...provided.droppableProps}
            >
              <Draggable draggableId="draggable-1" index={0}>
                {(provided, snapshot) => (
                    <div
                      ref={provided.innerRef}
                      {...provided.draggableProps}
                      {...provided.dragHandleProps}
                    >
                      <h4>My draggable</h4>
                    </div>
                )}
              </Draggable>
              {provided.placeholder}
            </div>
          )}
        </Droppable>
      </DragDropContext>
    );
  }
}
  • Draggable必须始终包含在Droppable中
  • DraggablebId(字符串):必须存在唯一ID,和index(如果为遍历 key也需要)不要更改此ID,特别是在拖动时

拖拽结束时,改变源数据

onDragEnd = result => {
  const { source, destination, draggableId } = result;
  if (!destination) {
    return;
  }

  // 修改源和目标数组,将拖拽元素从源数组中删除,再插入到目标数组中
  this.setState({
    xxx: xxx,
  });
}

使用过程中遇到的问题

向拖拽的目标区域增加自定义占位符(custom placeholder)

react-beautiful-dnd在拖拽到目标区域时,目标区域的元素之间会给当前拖拽元会自动空出一段space,这段space的距离是目标区域Draggable元素的大小(但不包括元素的margin边距,这也是一个坑,下文会说到解决方法)。

因此可以在这段距离中采用绝对定位,增加自定义占位符。具体做法:计算出当前自定义占位符元素的left & top距离,在dragUpdate事件中更新这两个距离,可参考beatiful-dnd-custom-placeholder-demo

拖拽时,修改拖拽元素的transform属性,导致拖拽会卡死在某处,拖拽元素放置位置错误

在官方文档中,有这样一段说明, 大概是说draggable元素采用了position: fixed定位,但会受到transform会影响。

#### Warning: `position: fixed`

`react-beautiful-dnd` uses `position: fixed` to position the dragging element. This is quite robust and allows for you to have `position: relative | absolute | fixed` parents. However, unfortunately `position:fixed` is [impacted by `transform`](http://meyerweb.com/eric/thoughts/2011/09/12/un-fixing-fixed-elements-with-css-transforms/) (such as `transform: rotate(10deg);`). This means that if you have a `transform: *` on one of the parents of a `<Draggable />` then the positioning logic will be incorrect while dragging. Lame! For most consumers this will not be an issue.

To get around this you can [reparent your <Draggable />](/docs/guides/reparenting.md). We do not enable this functionality by default as it has performance problems.

提供了如下解决方法:使用createPortal给拖动元素挂在空的父元素上,可参考issue: transform on parent messes up dragging positioning

但是这个方法并不能解决我的问题,因为还有自定义placeholder的需求。在拖拽时还需要计算placeholder的left的距离,也就需要获取当前拖拽元素的parentNode下的子元素,使用createPortal则获取不到拖拽元素的原parentNode,因此放弃createPortal的方案。采用改变width和height达到transform:scale的效果。

移动端拖拽元素需要长按该元素(long-press)

官方文档中给出的说明是,在移动端场景下,在draggable元素上的手指操作,无法确定是tap,force press,或者scroll,所以需要长按该元素才能确定是拖拽。

Starting a drag: long press
A user can start a drag by holding their finger 👇 on an element for a small period of time 🕑 (long press)

拖拽某个元素悬停在目标位置时,空出的插入space距离不准确的问题
这个就是上文中提到的,Draggable之间留的placeholder的空余距离是一个Draggable的距离,但不包括Dragglable的margin边距,可参考这个issue

最后采用padding来控制Draggable之间的距离,这样在拖拽时空出的space就包括了padding。

总结

react-beautiful-dnd比较容易上手, 到2021年3月发布了v13.1.0较为活跃, 以上踩过的坑,希望对大家有所帮助。

参考资料

官网beautiful-dnd
react-beautiful-dnd入门教程

到此这篇关于使用react-beautiful-dnd实现列表间拖拽踩坑 的文章就介绍到这了,更多相关react 列表拖拽内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 基于React.js实现原生js拖拽效果引发的思考

    一.起因&思路 一直想写一个原生js拖拽效果,又加上近来学react学得比较嗨.所以就用react来实现这个拖拽效果. 首先,其实拖拽效果的思路是很简单的.主要就是三个步骤: 1.onmousedown的时候,启动可拖拽事件,记录被拖拽元素的原始坐标参数. 2.onmousemove的时候,实时记录鼠标移动的距离,结合被拖拽元素第一阶段的坐标参数,计算并设置新的坐标值. 3.onmouseup的时候,关闭可拖拽事件,记录新的坐标值. 注意:这里主要是通过绝对定位的top和left来确定元素的位置

  • React 实现拖拽功能的示例代码

    本文介绍了React 实现拖拽功能的示例代码,分享给大家,具体如下: 实现效果: 因为工作中会用到 JIRA 所以想实现一下相似的功能,顺便学习一下 H5 的拖拽.不支持拖拽改变顺序,感觉有点麻烦,而且没必要.感觉相关的博文好少的,大部分都是直接上代码,没有解释. 图片默认可以拖动,其他元素的拖动效果同图片.正常的 div 是不能被拖动的,鼠标点击选择后移动没有效果,需要加  draggable="true" 使得元素可以被拖动. 拖拽相关的几个事件,有被拖动元素的事件,也有拖动进入的

  • 一百多行代码实现react拖拽hooks

    前言 源码总共也就一百多行,看完这个大致可以理解一些成熟的react拖拽库的实现思路,比如react-dnd,然后你上手这些库的时候就非常快了. 使用hooks实现的大致效果动图如下: 我们的目标是实现一个useDrag和useDrop的hooks,类似以下用法就可以轻松让元素可以拖拽,并且在拖拽的各个生命周期,如下,可以自定义传递消息(顺便介绍几个拖拽会触发的事件). dragstart:用户开始拖拉时,在被拖拉的节点上触发,该事件的target属性是被拖拉的节点. dragenter:拖拉进

  • react.js组件实现拖拽复制和可排序的示例代码

    在实现复制前,对之前的拖拽排序组件属性进行了修改. 摒弃了value中的content属性,拖拽组件暴露的render函数,利用这个属性进行组件内部子组件的渲染,这点主要是参考了蚂蚁金服的Ant design里面一些组件的设计. 为了实现Data和model的脱藕,和sortKey一样,组件增加codeKey属性. 拖拽复制的效果如下: 由于实现组件的核心是根据value数据来渲染页面,因此实现拖拽复制功能,只需要在"拖拽释放"的时候,将被拖拽方的数据放到当前目标所在的value数组中

  • 使用react-beautiful-dnd实现列表间拖拽踩坑

    为什么选用react-beautiful-dnd 相比于react-dnd,react-beautiful-dnd更适用于列表之间拖拽的场景,支持移动端,且较为容易上手. 基本使用方法 基本概念 DragDropContext:构建一个可以拖拽的范围 onDragStart:拖拽开始回调 onDragUpdate:拖拽中的回调 onDragEnd:拖拽结束时的回调 Droppable - 可以放置拖拽块的区域 Draggalbe - 可被拖拽的元素 使用方法 把你想能够拖放的代码放到DragDr

  • Vue使用vue-draggable 插件在不同列表之间拖拽功能

    今天分享一个vue项目中在不同列表拖拽设置选项的功能,这个功能也是在做项目中遇到的,先说下这个功能的要点(参考下图),有2个列表,左侧列表展示已选,右侧列表展示未选,通过拖拽进行设置,已选的选项不能超过4个,超过的话自动将拖拽之前的最后一项清除到右侧,且如果从已选往未选里拖的时候,右侧显示垃圾桶的提示(如图). 拖拽功能图片: 垃圾桶显示图: 首先讲讲vue-draggable的使用 安装vue-draggable: npm install vuedraggable 在使用插件的组件内引入vue

  • react优雅处理多条件鼠标拖拽位移

    本文实例为大家分享了react优雅处理多条件鼠标拖拽位移的具体代码,供大家参考,具体内容如下 场景 三种拖拽条件 可纵轴 横轴 和全部方向 如果加3个监听重复代码太多因为状态更改组件会重新渲染 所以写的时候要多注意避免有大量代码的函数多次创建销毁 state const [position, setPosition] = useState(axisPosition); jsx <Container       style={{         top: position.top + "px

  • Python 列表和字典常踩坑即解决方案

    目录 一.关于列表 1.问题描述 2.解决方案 方案一 方案二 二.关于字典 1.问题描述 2.解决方案 结论 前言: 在Python中,如果我们想要在遍历一组数据的过程中,对这组数据进行修改,通常会出现许多问题,例如对列表进行上述操作时, 会忽略部分数据:遍历字典时,不能修改数据.本文针对这些问题,提出了多种解决方案. 一.关于列表 1.问题描述 在Python中,如果你试图在遍历一组数据的过程中,对其进行修改,这通常没什么问题. 例如: l = [3, 4, 56, 7, 10, 9, 6,

  • 针对后台列表table拖拽比较实用的jquery拖动排序

    现在很多后台列表为了方便均使用拖拽排序的功能,对列表进行随意的排序. 话不多说 ,我在网上找了一些demo,经过对比,现在把方便实用的一个demo列出来,基于jqueryUI.js 先上html代码,很简单: 复制代码 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>jqueryUI拖动</title>

  • Vue实用功能之实现拖拽元素、列表拖拽排序

    目录 Vue实现拖拽元素.列表拖拽排序 组件使用 补充:排序动画 总结 Vue实现拖拽元素.列表拖拽排序 需求:    1.左右两个容器,左边和右边的元素可以拖动互换    2.列表拖拽排序 组件使用 Vue.Draggable是一款基于Sortable.js实现的vue拖拽插件支持移动设备.拖拽和选择文本.智能滚动,可以在不同列表间拖拽.不依赖jQuery为基础,vue2过渡动画兼容.支持撤销操作,总之是一款非常优秀的vue拖拽组件 npm或yarn安装方式 yarn add vuedragg

  • angular-ui-sortable实现可拖拽排序列表

    项目需求,添加列表可拖拽排序功能,谷歌了一下,找到一个Angular的插件:angular-ui-sortable,项目地址:https://github.com/angular-ui/ui-sortable 需要在之前引入jquery,和jquery-ui,否则无法使用. 我们要做的事情,加载数据,拖拽排序并输出当前顺序: js代码: <script src="../../jquery.js"></script> <script src="..

  • Android自定义ListView实现仿QQ可拖拽列表功能

    我们大致的思路,其实是这样子的,也是我的设想,我们可以先去实现一个简单的ListView的数据,但是他的Adapter,我们可以用系统封装好的,然后传递进去一个实体类,最后自定义一个listview去操作,所以我们先把准备的工作做好,比如? list_item.xml <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.a

  • React拖拽调整大小的组件

    本文实例为大家分享了React拖拽调整大小的组件,供大家参考,具体内容如下 一.实现流程 1.使用React.cloneElement加强包裹组件,在包裹的组件设置绝对定位,并在组件内加上四个可调整大小的拖动条,在点击拖动条并进行拖动时会改变DragBox的大小,如下: 2.使用: <DragBox dragAble={true} minWidth={350} minHeight={184} edgeDistance={[10, 10, 10, 10]} dragCallback={this.d

  • JS拖拽排序插件Sortable.js用法实例分析

    本文实例讲述了JS拖拽排序插件Sortable.js用法.分享给大家供大家参考,具体如下: 最近由于项目功能设计的原因,需要对table中的行实现拖拽排序功能,找来找去发现Sortable.js能很好的满足这个需求,而且它还是开源的,于是乎就开始学习使用Sortable.js,再然后就有了这篇文章. 特点: 轻量级但功能强大 移动列表项时有动画 支持触屏设备和大多数浏览器(IE9及以下除外) 支持单个列表容器内部拖拽排序,也支持两个列表容器互相拖拽排序 支持拖放操作和可选择的文本 非常友善的滚动

随机推荐