Skip to content

拖放事件

https://zh.javascript.info/mouse-drag-and-drop

https://www.yuque.com/qinsjs/jsinfo/qwgzut

js info 这一章并没有讲 drop 相关的事件。而是 move 的拓展

code
vue
<template>
  <div class="field" @mousemove="move" ref="field">
    <div
      class="ball"
      ref="ball"
      @mousedown="ballDown"
      @mouseup="ballUp"
      @dragstart.prevent
    >
      <img src="./ball.svg" />
    </div>

    <img class="soccer-gate" src="./soccer-gate.svg" />
  </div>
</template>

用 div 包住 img 是 hidden 的一个问题,不知道是特殊情况还是一直有这个问题。

vue
<script lang="ts" setup>
import { ref } from "vue";

// dom
const field = ref(null);
const ball = ref(null);

// 记录按下
let down = false;

// 鼠标按下时候,精准的坐标,相对坐标
const ballInfo = { shiftX: 0, shiftY: 0 };

// event 相对 field 的相对坐标。
// 因为 pageX、Y 是相对于 docment 的。
const getFieldContentXY = (pageX, pageY) => {
  const dom = field.value;
  const { x, y } = dom.getBoundingClientRect();

  const startX = pageX - x - dom.clientLeft;
  const startY = pageY - y - dom.clientTop;

  return { startX, startY };
};

// 移动小球
const updateBallxy = (e) => {
  const { pageX, pageY } = e;

  const dom = ball.value;

  //   field 内部的相对坐标
  const { startX, startY } = getFieldContentXY(pageX, pageY);

  // 根据指针按下时的相对坐标进行移动
  const { shiftX, shiftY } = ballInfo;

  dom.style.left = startX - shiftX + "px";
  dom.style.top = startY - shiftY + "px";
};

// 按下事件
const ballDown = (e) => {
  const { pageX, pageY } = e;
  const dom = ball.value;
  const ballRect = dom.getBoundingClientRect();

  // 记录下按下时 ball 的相对坐标
  ballInfo.shiftX = pageX - ballRect.x;
  ballInfo.shiftY = pageY - ballRect.y;

  updateBallxy(e);

  down = true;
};

const ballUp = (e) => {
  down = false;
};

// 移动事件
let currentDroppable;
const move = (e) => {
  if (!down) return;

  updateBallxy(e);

  // 光速 hidden ,获取小球下面的元素。
  ball.value.hidden = true;
  const elemBelow = document.elementFromPoint(e.clientX, e.clientY);
  ball.value.hidden = false;

  if (!elemBelow) return;

  if (currentDroppable && currentDroppable !== elemBelow) {
    currentDroppable.style.background = "";
  }

  currentDroppable = elemBelow;

  if (!elemBelow?.className.includes("field")) {
    elemBelow.style.background = "pink";
  }
};
</script>