拖动者

拖动器是一种控制器对象,用于协调拖动可拖动对象以响应用户互动。

在极少数情况下,您可能需要实现自定义拖动手柄,因为您可能不需要对协调拖动进行太多自定义。scroll-options 插件会实现自定义拖动器,因为它想要在工作区边缘添加滚动,从而更改像素坐标转换为工作区坐标的方式。

职责

拖动操作时,拖动者有以下几项责任:

  • 对可拖动对象调用拖动方法。
  • 计算可拖动对象应在工作区坐标中移动到的位置。
  • 对任何悬停的拖动目标调用拖动目标方法。

实现

如需创建自定义拖动器,您必须实现 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
  • 在拖动目标首次悬停时,应在 onDragEnter 之后调用 onDragOver;在拖动目标仍处于悬停状态的每次 onDrag 调用中,也应调用 onDragOver
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();
  }
}

注册

您需要注册拖动类,以便在检测到拖动操作时创建该类。

// 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);

用法

实现自定义拖动器后,您可以通过将其传递给注入配置结构体来使用它。

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,
  },
});