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事件中更新这两个距离,可参考

拖拽时,修改拖拽元素的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`]() (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.

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zygzgg.html