拖放事件
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>