拖曳

Dragger 是控制項物件,可在回應使用者互動時協調拖曳 draggables

您很少需要導入自訂拖曳工具,因為您不太可能需要自訂拖曳動作的協調方式。捲動選項外掛程式會實作自訂拖曳工具,因為它想在工作區邊緣新增捲動功能,藉此變更像素座標轉換為工作區座標的方式。

職責

執行拖曳動作時,拖曳器有幾項責任:

  • 在可拖曳的元件上呼叫拖曳方法。
  • 計算可拖曳項目在工作區座標中應移動的位置。
  • 在任何懸停的拖曳目標上呼叫拖曳目標方法。

實作

如要建立自訂拖曳器,您必須實作 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();
  }
}

註冊

您需要註冊拖曳器類別,才能在偵測到拖曳動作時建立拖曳器。

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