Kéo

Trình kéo là một đối tượng điều khiển điều phối thao tác kéo đối tượng có thể kéo để phản hồi các hoạt động tương tác của người dùng.

Có rất ít trường hợp bạn muốn triển khai một trình kéo tuỳ chỉnh, vì không có nhiều trường hợp mà bạn có thể muốn tuỳ chỉnh về việc điều phối một thao tác kéo. Trình bổ trợ tuỳ chọn cuộn triển khai một trình kéo tuỳ chỉnh vì trình bổ trợ này muốn thêm tính năng cuộn ở cạnh của không gian làm việc, điều này sẽ thay đổi cách toạ độ pixel được chuyển đổi thành toạ độ không gian làm việc.

Yêu cầu của công việc

Trình kéo có một số trách nhiệm khi thực thi thao tác kéo:

  • Gọi các phương thức kéo trên đối tượng có thể kéo.
  • Tính toán vị trí mà thành phần có thể kéo cần di chuyển đến trong toạ độ không gian làm việc.
  • Gọi các phương thức mục tiêu kéo trên bất kỳ mục tiêu kéo nào được di chuột qua.

Triển khai

Để tạo một trình kéo tuỳ chỉnh, bạn phải triển khai giao diện IDragger.

class MyDragger implements IDragger {
  // Takes in the draggable being dragged and the workspace the drag
  // is occurring in.
  constructor(draggable, workspace);
}

Bạn cũng có thể tạo lớp con cho Blockly.dragging.Dragger tích hợp sẵn, lớp này đã xử lý các trách nhiệm cơ bản.

Bắt đầu kéo

Phương thức onDragStart khởi tạo một thao tác kéo. Tệp này nên lưu trữ mọi dữ liệu cần thiết để thực thi thao tác kéo. Thao tác này cũng sẽ gọi startDrag trên đối tượng có thể kéo đang được kéo.

onDragStart(e) {
  this.startLoc = this.draggable.getRelativeToSurfaceXY();

  this.draggable.startDrag(e);
}

Phương trình lực cản

Phương thức onDrag thực thi một thao tác kéo. Hàm này sẽ tính toán vị trí không gian làm việc mới cho đối tượng có thể kéo dựa trên totalDelta, được cung cấp theo toạ độ pixel.

Thao tác này cũng sẽ cập nhật mọi mục tiêu kéo đang được di chuột qua.

  • Bạn phải luôn gọi wouldDelete trước khi gọi các trình bổ trợ khác trên mục tiêu kéo.
  • Bạn phải luôn gọi onDragExit trên mục tiêu kéo cũ trước khi gọi onDragEnter trên mục tiêu kéo mới.
  • onDragOver phải được gọi sau onDragEnter trong lần đầu tiên di chuột mục tiêu kéo và trên mỗi lệnh gọi bổ sung đến onDrag mà mục tiêu kéo vẫn được di chuột.
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;
}

Kết thúc các lượt kéo

Phương thức onEndDrag kết thúc thao tác kéo. Phương thức này sẽ thông báo cho đối tượng có thể kéo rằng thao tác kéo đã kết thúc và mọi mục tiêu kéo được di chuột qua mà đối tượng có thể kéo đã được thả. Thao tác này cũng phải loại bỏ thành phần có thể kéo nếu mục tiêu kéo là vùng xoá.

  • Luôn gọi onDrop trước các phương thức khác.
  • Bạn nên gọi revertDrag nếu mục tiêu kéo ngăn chặn thao tác kéo.
  • endDrag phải được gọi sau khi hoàn nguyên thao tác kéo, nhưng trước khi loại bỏ.
  • dispose sẽ được gọi nếu mục tiêu kéo là một vùng xoá.
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();
  }
}

Đăng ký

Bạn cần đăng ký lớp kéo để có thể tạo lớp này khi phát hiện thao tác kéo.

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

Cách sử dụng

Sau khi triển khai trình kéo tuỳ chỉnh, bạn có thể sử dụng trình kéo đó bằng cách truyền trình kéo đó vào cấu trúc cấu hình chèn.

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