文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

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

2024-04-02 19:55

关注

为什么选用react-beautiful-dnd

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

基本使用方法

基本概念

使用方法

把你想能够拖放的代码放到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>
    );
  }
}

在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>
    );
  }
}

拖拽结束时,改变源数据


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 列表拖拽内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-前端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯