最近项目中用到了一个新依赖 react-beautiful-dnd,在这里记录一下使用的过程及遇到的一些坑。
引入
此依赖用于React框架。
使用 npm i react-beautiful-dnd --save
安装。
安装完毕后,在需要使用拖拽元素功能的页面引入组件。
import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd"
结构
react-beautiful-dnd 官方对于使用拖拽组件的结构用了一张图片标识,这张图很清晰地展示了拖拽元素所处的结构关系。
<DragDropContext>
:最外层包裹拖拽区域的wrap。
<Droppable>
:某个包含若干个可拖拽项的组。
<Draggable>
:可拖拽项。
我使用的是最简单的若干个项拖拽, 以下是我的原代码结构
<div className="myModal">
<div className="modalList">
{this.state.modalListInModal.map((item) => (
<div className="modal" key={item.name}>
<img src={item.imgUrl} alt="" />
<span title={item.wording}>{item.wording}</span>
</div>
))}
</div>
</div>
按照上面的gif图结构,我写出了如下结构
<DragDropContext onDragEnd={this.onDragEnd}>
<div className="myModal">
<Droppable droppableId="mymodal" direction="horizontal">
{(provided) => (
<div
className="modalList"
ref={provided.innerRef}
{...provided.droppableProps}>
{this.state.modalList.map((item, index) => (
<Draggable draggableId={item.name} index={index} key={item.name}>
{(provided) => (
<div
className="modal"
key={item.name}
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}>
<img src={item.imgUrl} alt="" />
<span title={item.wording}>{item.wording}</span>
</div>
)}
</Draggable>
))}
{provided.placeholder}
</div>
)}
</Droppable>
</div>
</DragDropContext>
可以看到,我在最外层的 .myModal
div盒子套了一层 DragDropContext
作为容器;
而 Droppable
在我包裹map的.modalList
之外;
最内部则是每一个可以拖拽的实例modal
,它是被 map > Draggable
> modal 这样一层层包裹。
注意事项
-
DragDropContext
可选五个函数作为参数<DragDropContext onBeforeCapture={this.onBeforeCapture} onBeforeDragStart={this.onBeforeDragStart} onDragStart={this.onDragStart} onDragUpdate={this.onDragUpdate} onDragEnd={this.onDragEnd} />
写好了上面的结构,必须在
onDragEnd
回调中告诉react,用户拖拽的改变结果。也就是传递改变后的state给react,否则拖拽在松开鼠标后会恢复到拖拽前的顺序。 以下是我onDragEnd的函数参考。// 拖拽调整顺序 onDragEnd = (result) => { const sourceIndex = result.source.index; const destinationIndex = result.destination.index; if (sourceIndex === destinationIndex) { return; } const userList = deepClone(this.state.modalList); const [draggedItem] = userList.splice(sourceIndex, 1); userList.splice(destinationIndex, 0, draggedItem); this.setState({ modalList: userList, }); };
onDragEnd是一个对象,它会传递一些信息让我们利用。
{ "draggableId": "leetCode", "type": "DEFAULT", "source": { "index": 1, "droppableId": "mymodal" }, "reason": "DROP", "mode": "FLUID", "destination": { "droppableId": "mymodal", "index": 2 }, "combine": null }
其中最重要的是源位置(source)和目标位置(destination),里面有我们原来的位置和拖拽最终所在的位置,我们利用这两个index拿到源item并调整到目的位置。 最后记得setState
-
Droppable
和Draggable
结构的props 第二层结构需要添加 droppableId 和 方向,水平为horizontal,竖直方向为vertical<Droppable droppableId="mymodal" direction="horizontal">
第三层结构需要添加 draggableId 和 index 以及 key,这几个都是用于区分不同项的手段。draggableId={item.name} index={index} key={item.name}
-
Droppable
和Draggable
结构内包的 箭头函数 及 div内的参数 二层和三层包裹的必须是一个返回原本html结构的 函数, provided是官方提供的参数,里面包含着拖拽一系列参数,事件监听等。 div内的参数为固定写法,照抄即可。第二层 div ref={provided.innerRef} {...provided.droppableProps} 第三层 div ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}
-
最后,在map结束到 Droppable结束 之间的位置放一个
{provided.placeholder}
,用于为拖动的元素占位。 以上提到的一些参数属于必写,不写就会有error或者bug。 感谢开源项目避免了让我花费时间造轮子,最后放一下这个依赖的github地址。 atlassian/react-beautiful-dnd