拖动对象是一种控制器对象,可协调拖动可拖动对象以响应用户互动。
在极少数情况下,您需要实现自定义拖动操作,因为在协调拖动操作方面不需要自定义的太多内容。scroll-options 插件实现了自定义拖动器,因为它希望在工作区边缘添加滚动效果,这会更改像素坐标转换为工作区坐标的方式。
职责
在执行拖动操作时,Dragger 承担多项责任:
- 对可拖动对象调用拖动方法。
- 按工作区坐标计算可拖动项应移至的位置。
- 对任何悬停的拖动目标调用拖动目标方法。
实现
如需创建自定义拖动器,您必须实现 IDragger
接口。
class MyDragger implements IDragger {
// Takes in the draggable being dragged and the workspace the drag
// is occurring in.
constructor(draggable, workspace);
}
您还可以创建已处理基本职责的内置 Blockly.dragging.Dragger
的子类。
开始拖动
onDragStart
方法用于初始化拖动操作。它应该存储执行拖动所需的所有数据。此外,它还应对正在拖动的可拖动对象调用 startDrag
。
onDragStart(e) {
this.startLoc = this.draggable.getRelativeToSurfaceXY();
this.draggable.startDrag(e);
}
拖动
onDrag
方法用于执行拖动操作。它应根据以像素坐标表示的 totalDelta
计算可拖动项的新工作区位置。
它还应该会更新悬停在上面所有的拖动目标。
- 在对拖动目标调用其他钩子之前,应始终调用
wouldDelete
。 - 应始终对旧拖动目标调用
onDragExit
,然后再对新拖动目标调用onDragEnter
。 onDragOver
应在拖动目标首次悬停在onDragEnter
之后以及每次再次调用onDrag
时(即拖动目标仍处于悬停状态)时调用。
onDrag(e, totalDelta) {
// Update the draggable location.
const delta = this.pixelsToWorkspaceUnits(totalDelta);
const newLoc = Coordinate.sum(this.startLoc, delta);
this.draggable.drag(newLoc, e);
// Call wouldDeleteDraggable.
if (isDeletable(this.draggable)) {
this.draggable.setDeleteStyle(
// Checks that the drag target is an `IDeleteArea` and calls `wouldDelete`
// on it.
this.wouldDeleteDraggable(e, this.draggable),
);
}
const newDragTarget = this.workspace.getDragTarget(e);
if (this.dragTarget !== newDragTarget) {
// Call `onDragExit` then `onDragEnter`.
this.dragTarget?.onDragExit(this.draggable);
newDragTarget?.onDragEnter(this.draggable);
}
// Always call `onDragOver`
newDragTarget?.onDragOver(this.draggable);
this.dragTarget = newDragTarget;
}
结束拖动
onEndDrag
方法可结束拖动。它应通知可拖动对象拖动已结束,并通知可拖动对象已拖动的任何悬停的拖动目标。如果拖动目标是删除区域,它也应处置可拖动对象。
- 应始终先调用
onDrop
,然后再调用其他方法。 - 如果拖动目标阻止拖动,则应调用
revertDrag
。 - 应在还原拖动之后但处置之前调用
endDrag
。 - 如果拖动目标为删除区域,应调用
dispose
。
onDragEnd(e) {
// Call `onDrop` first.
const dragTarget = this.workspace.getDragTarget(e);
if (dragTarget) {
this.dragTarget?.onDrop(this.draggable);
}
// Then revert the drag (if applicable).
if (this.shouldReturnToStart(e, this.draggable)) {
this.draggable.revertDrag();
}
// Then end the drag.
this.draggable.endDrag(e);
// Then delete the draggable (if applicable).
if (
isDeletable(this.draggable) &&
this.wouldDeleteDraggable(e, this.draggable)
) {
this.draggable.dispose();
}
}
注册
需要注册 Dragger 类,以便在检测到拖动时创建它。
// Note that the type is BLOCK_DRAGGER even though draggers drag more than
// blocks. The name is for backwards compatibility.
Blockly.registry.register(registry.Type.BLOCK_DRAGGER, 'MY_DRAGGER', MyDragger);
用量
实现自定义 Dragger 后,您就可以将其传递给注入配置结构体,从而使用该程序。
const myWorkspace = Blockly.inject('blocklyDiv', {
plugins: {
// Note that we pass this to blockDragger even though draggers drag more
// than blocks. The name is for backwards compatibility.
blockDragger: MyDragger,
},
});