拖动者

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

在极少数情况下,您需要实现自定义拖动操作,因为在协调拖动操作方面不需要自定义的太多内容。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,
  },
});