react 分页列表优化(使用react-beautiful-dnd实现列表间拖拽踩坑)
react 分页列表优化
使用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} > <li>Hello world</li> </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) => ( <li ref={provided.innerRef} style={{ backgroundColor: snapshot.isDraggingOver ? 'blue' : 'grey' }} {...provided.droppableProps} > <h2>I am a droppable!</h2> {provided.placeholder} </li> )} </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) => ( <li ref={provided.innerRef} style={{ backgroundColor: snapshot.isDraggingOver ? 'blue' : 'grey' }} {...provided.droppableProps} > <Draggable draggableId="draggable-1" index={0}> {(provided, snapshot) => ( <li ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps} > <h4>My draggable</h4> </li> )} </Draggable> {provided.placeholder} </li> )} </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 列表拖拽内容请搜索开心学习网以前的文章或继续浏览下面的相关文章希望大家以后多多支持开心学习网!
- react常用设计模式(提高React界面性能的十个技巧)
- react源码教程(详解React 代码共享最佳实践方式)
- react 使用实例(React+高德地图实时获取经纬度,定位地址)
- react新手指引页面编写(React+TypeScript进行项目构建案例讲解)
- react怎么使用父组件(关于antd tree和父子组件之间的传值问题react 总结)
- reactmap给了key仍然提示错误(react为什么不推荐使用index作为key)
- react 封装下拉选择框(React鼠标多选功能的配置方法)
- react自适应布局如何实现(React实现分页效果)
- react路由原理解析(React配置子路由的实现)
- vscode react插件(基于visual studio code + react 开发环境搭建过程)
- vue3中的setup的参数(Vue3中ref与reactive的详解与扩展)
- react动态创建菜单并实现局部刷新(使用react-virtualized实现图片动态高度长列表的问题)
- react子组件的动态参数(浅谈React Component生命周期函数)
- react定时任务(手把手带你用React撸一个日程组件)
- 使用react生命周期的常见情况(react+ts实现简单jira项目的最佳实践记录)
- react性能优化是哪个周期(React 并发功能体验前端的并发模式)
- 小米音乐与 QQ 音乐合作,便捷迁移会员(小米音乐与QQ音乐合作)
- 小米推出米兔儿童电话手表奥特曼版,799 元,支持微信 QQ(小米推出米兔儿童电话手表奥特曼版)
- 贾怀胤唱《白龙马》 炸场 了 没想到京剧还能这么玩(贾怀胤唱白龙马)
- 白龙马的改编学生版,快来看看(白龙马的改编学生版)
- 萌娃唱《白龙马》走红,那生动的小表情,网友直呼 简直是戏精(萌娃唱白龙马走红)
- 朱鹤松被不断认可,凤凰传奇玲花喊话岳云鹏,索要老朱演出门票(朱鹤松被不断认可)
热门推荐
- Asp.net导出Excel乱码
- vue3 props用法(vue3组合API中setup、 ref、reactive的使用大全)
- vs远程调试
- yii2对比springboot(yii2.0框架使用 beforeAction 防非法登陆的方法分析)
- python设计一个聊天机器人(手把手教你使用Python创建微信机器人)
- mysql 高效分页(MySQL 分页查询的优化技巧)
- mysql 内置函数
- mysql8.0.16安装步骤图解(mysql 8.0.22 安装配置图文教程)
- css3渐变样式怎么用(CSS3 background-image颜色渐变的实现代码)
- python3.7.2 详细安装教程(python3.5安装python3-tk详解)
排行榜
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9