Перетаскивание блока по экрану, не срабатывает onmouseup
Когда только начинаю перемещать блок, он на пару пикселей смещаеся вправо и вниз относительно мышки. Таким образом, если курсор установить где-то очень близко к верхней левой границе блока, при самом начале перетаскивания блок ускользает из-под мышки на пару пикселей и у него перестаёт работать onmouseup.
Поясните, почему так происходит и откуда могут браться эти 3-4 пикселя?
На самом деле, почему-то в редакторе кода stackoverflow он съезжает на куда большее количество пикселей, поэтому лучше скопировать код в IDE для полного воспроизведения ошибки.
//Список окон потому, что в оригинальном коде их может быть больше одного.
wins = [...document.getElementsByClassName('window')];
function init() {
wins.forEach(win => {
win.onmousedown = function(event) {
//Смещение для координат, так как event даёт координаты относительно viewport, а задаём мы координаты относительно родительского блока.
win.shiftX = event.clientX - win.getBoundingClientRect().left + win.parentElement.getBoundingClientRect().left;
win.shiftY = event.clientY - win.getBoundingClientRect().top + win.parentElement.getBoundingClientRect().top;
//Функция перемещения блока. Также проверяет на пересечение границ родительского блока, иначе по каким-то причинам onmouseup тоже не срабатывает. Также применяет смещение.
function moveAt(pageX, pageY) {
if(pageX >= win.parentElement.getBoundingClientRect().right
|| pageX <= win.parentElement.getBoundingClientRect().left
|| pageY >= win.parentElement.getBoundingClientRect().bottom
|| pageY <= win.parentElement.getBoundingClientRect().top) {
document.removeEventListener('mousemove', win.onMouseMove);
return;
}
//console.log(pageX, win.shiftX, pageX - win.shiftX);
win.style.left = pageX - win.shiftX + 'px';
win.style.top = pageY - win.shiftY + 'px';
}
win.onMouseMove = function(event) {
moveAt(event.pageX, event.pageY);
}
document.addEventListener('mousemove', win.onMouseMove);
win.onmouseup = function() {
document.removeEventListener('mousemove', win.onMouseMove);
win.onmouseup = null;
};
}
//Чтобы браузерный drag-n-drop не мешался.
win.ondragstart = function() {
return false;
};
});
}
init();
.window {
box-sizing: border-box;
position: absolute;
border: 1px solid red;
background-color: white;
}
.surface {
box-sizing: border-box;
position: absolute;
margin: 0 0 0 0;
overflow: hidden;
top: 100px;
left: 100px;
border: 5px solid green;
width: 600px;
height: 400px;
}
#id-1 {
left: 100px;
top: 100px;
width: 100px;
overflow: hidden;
}
.unselectable {
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Chrome/Safari/Opera */
-khtml-user-select: none; /* Konqueror */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none; /* Non-prefixed version, currently
not supported by any browser */
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div class="surface">
<div class="window unselectable" id="id-1">
<p>Window</p>
</div>
</div>
<script type="text/javascript" src="script.js"></script>
</body>
</html>
Ответы (1 шт):
Надеюсь тут более менее понятно будет, то что у вас отсчет position: absolute; top: ... идет со внутренней границы обводки.
А getBoundingClientRect наоборот по внешней определяет. И получается граница выпадает из ваших расчетов.
const box = document.querySelector('.container');
const rect = box.getBoundingClientRect();
console.log(rect.top); // равен отступу элемента с учетом границы. В данном случае равен margin-top.
* {
margin: 0;
}
.container {
width: 150px;
height: 100px;
border: 10px solid green;
margin: 100px auto 0;
box-sizing: border-box;
position: relative;
}
.block {
position: absolute;
box-sizing: border-box;
top: 0; /* вот тут не с верхней границы, а с нижней границы обводки. Стоит 0, но отступ равен ширине обводки*/
width: 10px;
height: 10px;
background-color: red;
}
<div class="container">
<div class="block"></div>
</div>