这是2个组合事件
dom对象分源对象和目标对象
绑定的事件也是分别区分源对象和目标对象
事件绑定
事件顺序
被拖拽元素,事件触发顺序是 dragstart->drag->dragend;
对于目标元素,事件触发的顺序是 dragenter->dragover->drop/dropleave。
其中drag
和dragover
会分别在源元素和目标元素反复触发。整个流程一定是dragstart
第一个触发,dragend
最后一个触发。
这里还有一个注意的点,如果某个元素同时设置了dragover
和drop
的监听,那么必须阻止dragover
的默认行为,否则drop
将不会被触发。
问题
drop事件里面的e.offsetY会收到目标对象内部的子节点影响(如果在目标节点的子节点上是否标签),拿到是相对子节点内部的x,y距离。
修复:
- dragstart回调中给所有目标对象的子简单添加样式pointerEvents:none;让他们不会接受任何事件
- dragend的时候,恢复所有对象目标子节点的样式为:pointerEvents:auto;
demo:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
.wrap {
height: 400px;
overflow: auto;
background-color: beige;
}
.inner {
height: 1900px;
position: relative;
}
.draggable {
bottom: 10px;
right: 10px;
width: 100px;
height: 100px;
background-color: rebeccapurple;
position: fixed;
}
.inner_box {
top: 1800px;
right: 10px;
width: 100px;
height: 100px;
background-color: rebeccapurple;
position: absolute;
}
</style>
</head>
<body>
<div class="wrap">
<div class="inner">
<div class="inner_box"></div>
</div>
</div>
<div draggable="true" class="draggable"></div>
<script>
const inner = document.querySelector(".inner");
const source = document.querySelector(".draggable")
const inner_box=document.querySelector(".inner_box");
inner.addEventListener("dragover", (e) => {
e.preventDefault();
console.log("e.offsetY over", e.offsetY, e.target)
});
inner.dragenter = function (e) {
console.log("e enter", e.offsetY)
}
//源目标开始拖拽时候
source.addEventListener("dragstart", (e) => {
console.log("e start", e.offsetY)
//inner_box.style.pointerEvents="none";
});
inner.ondrop = function (e) {
console.log("e", e.offsetY)
}
</script>
</body>
</html>
参考
看完就懂的前端拖拽那些事 - 掘金
HTML 拖放(Drag and Drop)入坑实战总结篇 - 掘金
两个事件直接传递数据
DataTransfer
参考:https://www.cnblogs.com/guo-siqi/p/16358323.html