简介
这个库恰好最近看到别人的分析比较多,觉得也比较值得看一下
拖拽库
- react-dnd 除了列表操作,还有拖拽进去,随意拖拽某个位置,
- react-beautiful-dnd 专注于列表拖拽 貌似是后起之秀
- react-draggable 容器内位置的拖拽
Sortable
React Dnd
核心概念
https://react-dnd.github.io/react-dnd/docs/overview
- item是看到可拖拽的对象,原始就是一个js的对象,而不是dom或其他
- type即定义类型用来区分不同的drag和drop,以及drag和drop的匹配
- monitor 即保存了拖拽对象是否拖拽中状态,以及拖放容器状态,并暴露给组件来响应state的变化
- Connectors?这是啥?
- Drag Sources and Drop Targets 比较弱化了
- Backends 不同的拖砖容器,有html5或touch
- Hooks vs Higher-Order Components Decorator
提供API的模式
Hooks
Decorator
思考这两者的特性
核心的对象monitor
- DragSourceMonitor
canDragisDragginggetItemTypegetItem 当前拖拽的getDropResultgetClientOffset
- DropTargetMonitor
canDropisOvergetItemTypegetItem 当前拖拽的对象getDropResult
- DragLayerMonitor
如何分层的 DragDropManager
backend ->
store -> redux的store,reducers和actions
monitor -> SourceMonitor, TargetMonitor
manager -> DragDropManager
Connector -> SourceConnector,TargetConnector
背后的核心dragdropManager
export function createDragDropManager(backendFactory: BackendFactory,globalContext: unknown = undefined,backendOptions: unknown = {},debugMode = false,): DragDropManager {const store = makeStoreInstance(debugMode)const monitor = new DragDropMonitorImpl(store, new HandlerRegistryImpl(store))const manager = new DragDropManagerImpl(store, monitor)const backend = backendFactory(manager, globalContext, backendOptions)manager.receiveBackend(backend)return manager}// 1 store, 即redux定义的store,在reducers中的数据,如下的state// 即整个storeexport interface State {dirtyHandlerIds: DirtyHandlerIdsStatedragOffset: DragOffsetState // 当前拖拽的refCount: RefCountStatedragOperation: DragOperationStatestateId: StateIdState}// 2 monitor 提供访问当前拖拽状态的对象,拖拽的对象,拖拽的位置等// registry, drag, drop实例都会注册到registry属性// 背后通过访问registry以及store,来获取各信息,也就是个中间商,封装简化对内部store中数据的访问,// 3 actions 即redux中的action,抽象了各种操作的actions,beginDrag,endDrag,drop等,然后action会处理数据逻辑// 最终返回payload,通过dispatch更新到store中// 4 backend 即html5等backend,抽象了底层各平台的细节差异,// 以html5-backend为例//
有哪些设计模式等学习的
beginDrag中的createBeginDrag的factory工厂模式
整个流程是如何的?如果你拖动了一个元素会发生什么?
connectDragSource(sourceId, node, options) -> handleDragStart handleSelectStart
1 handleDragStart dragStartSourceIds.unshift(sourceId)
2 this.actions.beginDrag(dragStartSourceIds) 这背后做了很多逻辑
3
handleTopDragStart 即window上绑定的事件
export class HTML5BackendImpl implements Backend {// React-Dnd Componentsprivate actions: DragDropActionsprivate monitor: DragDropMonitorprivate registry: HandlerRegistryprivate sourcePreviewNodes: Map<string, Element> = new Map()private sourceNodes: Map<string, Element> = new Map()private dragStartSourceIds: string[] | null = nullprivate dropTargetIds: string[] = []private currentDragSourceNode: Element | null = nullpublic connectDragSource(sourceId: string,node: Element,options: any,): Unsubscribe {this.sourceNodes.set(sourceId, node)this.sourceNodeOptions.set(sourceId, options)const handleDragStart = (e: any) => this.handleDragStart(e, sourceId)const handleSelectStart = (e: any) => this.handleSelectStart(e)node.setAttribute('draggable', '' + this.monitor.canDragSource(sourceId))node.addEventListener('dragstart', handleDragStart)node.addEventListener('selectstart', handleSelectStart)// 返回解绑的方法return ...}public handleTopDragStart = (e: DragEvent): void => {// Don't publish the source just yet (see why below)this.actions.beginDrag(dragStartSourceIds || [], {publishSource: false,getSourceClientOffset: this.getSourceClientOffset,clientOffset,})if (this.monitor.isDragging()) {if (dataTransfer && typeof dataTransfer.setDragImage === 'function') {const sourceId: string = this.monitor.getSourceId() as stringconst sourceNode = this.sourceNodes.get(sourceId)const dragPreview = this.sourcePreviewNodes.get(sourceId) || sourceNode...}}}}
React Beautiful Dnd
特征?
性能高?虚拟
简洁的API
强大的场景和功能
核心概念
- DragDropContext 核心的manager,onDragEnd
- 一个DragDropContext里可以有多个Droppable
- Droppable
- provided,snapshot,droppableId
- Draggable
- provided,snapshot,draggableId
https://codesandbox.io/s/ql08j35j3q 多个Droppable,即两列进行拖拽
https://codesandbox.io/s/k260nyxq9v 最简单的入门demo,可拖拽排序的垂直列表
https://github.com/atlassian/react-beautiful-dnd/blob/master/docs/about/design-principles.md 设计原则
为什么有了react-dnd,还做了这个?
react-beautiful-dnd is a higher level abstraction specifically built for lists (vertical, horizontal, movement between lists, nested lists and so on)
React Dnd VS React Beautiful Dnd
| DnD | Beautiful Dnd | |
|---|---|---|
| 核心概念 | - DndProvider - Drag - Drop 通过此类处理事件 - DragDropManager 背后隐藏的 |
- DragDropContext 核心的manager,通过此来处理事件 - Draggable Component - Droppable Component |
| 暴露方式 | hooks或hoc | render props |
| drop对象处理 | 顶层context处理 | |
| 排序移动处理方式 | 拖拽排序需要自己写很多处理逻辑,位置判断等,有点偏底层。概念用drop也不太好理解 排序的example |
onDragEnd只暴露startIndex, endIndex,自己处理移动的数据操作 |
两个不同的设计思想
React Draggable
借鉴
http://www.ayqy.net/blog/react-dnd/
https://medium.com/@alexandereardon/rethinking-drag-and-drop-d9f5770b4e6b
https://www.npmtrends.com/react-beautiful-dnd-vs-react-dnd-vs-react-draggable
