概览
概览
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的单元格,那么你的代码可能是这样的:
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来创建一些预定义的拖拽角色(例如拖拽源,拖拽预览和放置对象)。 预定义一个放置对象可以像下面这样:
function collect(connect, monitor) {
return {
highlighted: monitor.canDrop(),
hovered: monitor.isOver(),
connectDropTarget: connect.dropTarget()//预定义放置目标并通过props返回
}
}
这样在渲染函数中就可以使用预定义的放置对象:
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>
);
}