梦亦同趋
首页
记忆
链接
reactdnd

概览

Aling
2023-08-28
阅读时长

#Item和Types

和Flux一样,react-dnd基于数据来驱动视图。所以当你在屏幕上拖动某个元素时我们不会说拖动了某个元素或者Dom节点,我们将其描述成某种Type下的某个Item正在被拖动。

那么这个Item是什么?其实就是记录了拖动信息的一个javascript对象。例如在一个看板中你拖动一个卡片,这个对象就可能是这样的{ cardId: 42 }。或者在象棋游戏中你拖动了一个棋子,这个对象 可能是这样的{ fromCell: 'C5', piece: 'queen' }。将被拖动的数据描述成对象有利于组件的解耦独立,这种设计的好处我们不久后就能看到。

Type是什么?Type在语法上是一个唯一的javascript字符串或者Symbol,用于将Item分组。例如看板应用中有可拖拽的卡片,也有列表中可拖拽排序的条目,你肯定不希望拖拽卡片经过列表时页面列表产生反应,通过将不同类型的Item分组使react-dnd内部能区分Item类型上的差异并做出正确的反应。

#监视器(Monitors)

拖拽是一种有状态的操作。拖拽操作要么在进行中要么就没有。这种状态需要被存储在一个地方,react-dnd通过监听器存储状态并将这些状态暴露出给开发者,开发者可以监听这些状态来处理拖拽逻辑。 你可以通过定义一个collect函数来从监视器中获取拖拽的状态,react-dnd会及时调用你定义的collect函数并将其返回值合并到组件的props中。例如刚刚提到的象棋游戏,现在我们想在棋子被拖动时高亮可放置的单元格并且在棋子hover的位置显示特殊的效果,那么我们需要获取到可被放置的单元格和当前被hover的单元格,那么你的代码可能是这样的:

js
function collect(monitor) { return { highlighted: monitor.canDrop(), hovered: monitor.isOver() } }

highlighted和hovered将会作为props传递给组件。于是我们可以基于这两个prop渲染页面。

#接口参数(Connectors)

之前安装react-dnd是安装了两个独立的包,有backend后缀的包是专门处理拖拽逻辑的。分包是为了方便扩展(例如之前提到的用mouseEvent自定义backend),不过这样就会有一个问题,我们使用backend来处理Dom事件,而react组件与其是独立的,使用时也只是在应用外包了一层高阶组件。那么backend内部怎么知道自己应该监听哪些Dom节点,哪些组件是可拖拽的,哪些又是可以放置组件。 这时候我们需要用到Connectors。在collect方法中,实际上Connectors是该方法的第一个参数,通过在方法内部调用collect提供的API来创建一些预定义的拖拽角色(例如拖拽源,拖拽预览和放置对象)。 预定义一个放置对象可以像下面这样:

js
function collect(connect, monitor) { return { highlighted: monitor.canDrop(), hovered: monitor.isOver(), connectDropTarget: connect.dropTarget()//预定义放置目标并通过props返回 } }

这样在渲染函数中就可以使用预定义的放置对象:

js
const render = ()=>{ const { highlighted, hovered, connectDropTarget } = this.props; //该元素将是放置目标且可被`backend`监听 return connectDropTarget( <div className={classSet({ 'Cell': true, 'Cell--highlighted': highlighted, 'Cell--hovered': hovered })}> {this.props.children} </div> ); }
上次更新:2025-07-07 15:46:57
上一篇
组件
下一篇
Document Updates