⛺️第2期第4题:实现一个拖拽(兼容写法)
Opened this issue · 3 comments
LinDaiDai commented
实现一个拖拽(兼容写法)
考察知识点
event
的兼容性
- 其它浏览器
window.event
- 火狐下没有
window.event
,所以用传入的参数ev
代替 - 最终写法:
var oEvent = ev || window.event
- 实现拖拽的事件有哪些(
box
为需要拖拽的元素)
box.onmousedown
document.onmousemove
box.onmouseup
- 实现的事件顺序
- 首先监听
box.onmousedown
,即鼠标按下box
时触发的事件,记录下鼠标按下时距离屏幕上边和左边的距离,以及box
距离屏幕上边和左边的距离,再用前者减去后者得到差值distanceX
和distanceY
- 然后在此事件中监听
document.onmousemove
事件,记录下每次鼠标移动时距离屏幕上边和左边的距离,然后用它们减去distanceX
和distanceY
,再将其赋值给box
的left
和top
,使其能跟着鼠标移动 - 不过需要考虑
box
距离屏幕最上面/下面/左边/右边的边界情况 - 当
box.onmouseup
的时候需要将document.onmousemove
事件设置为null
如图所示:
Coding
css
<style>
html, body {
margin: 0;
height: 100%;
}
#box {
width: 100px;
height: 100px;
background-color: red;
position: absolute;
top: 100px;
left: 100px;
}
</style>
html
<div id="box"></div>
javascript
window.onload = function () {
var box = document.getElementById('box');
box.onmousedown = function (ev) {
var oEvent = ev || window.event; // 兼容火狐,火狐下没有window.event
var distanceX = oEvent.clientX - box.offsetLeft; // 鼠标到可视区左边的距离 - box到页面左边的距离
var distanceY = oEvent.clientY - box.offsetTop;
document.onmousemove = function (ev) {
var oEvent = ev || window.event;
var left = oEvent.clientX - distanceX;
var top = oEvent.clientY - distanceY;
if (left <= 0) {
left = 0;
} else if (left >= document.documentElement.clientWidth - box.offsetWidth) {
left = document.documentElement.clientWidth - box.offsetWidth;
}
if (top <= 0) {
top = 0;
} else if (top >= document.documentElement.clientHeight - box.offsetHeight) {
top = document.documentElement.clientHeight - box.offsetHeight;
}
box.style.left = left + 'px';
box.style.top = top + 'px';
}
box.onmouseup = function () {
document.onmousemove = null;
box.onmouseup = null;
}
}
}
Turbo328 commented
box.onmouseup = function () { document.onmousemove = null; box.onmouseup = null;}
呆呆大佬,这里的mouseup事件的监听对象改成document会不会比较好呢?
如果是box的话,当鼠标超出box的范围,就无法监听到该事件并触发监听函数了;
场景是当按下鼠标拖拽box至超出页面范围(进入浏览器顶部菜单栏等等)并释放鼠标,然后再回到box中,会发现虽然鼠标处在释放的状态,但仍然可以拖拽box;
原因是鼠标并不是在box内部抬起的,所以并没有触发box的mouseup事件的监听函数,所以document的mousemove事件并没有移除。
LinDaiDai commented
box.onmouseup = function () { document.onmousemove = null; box.onmouseup = null;}
呆呆大佬,这里的mouseup事件的监听对象改成document会不会比较好呢?
如果是box的话,当鼠标超出box的范围,就无法监听到该事件并触发监听函数了;
场景是当按下鼠标拖拽box至超出页面范围(进入浏览器顶部菜单栏等等)并释放鼠标,然后再回到box中,会发现虽然鼠标处在释放的状态,但仍然可以拖拽box;
原因是鼠标并不是在box内部抬起的,所以并没有触发box的mouseup事件的监听函数,所以document的mousemove事件并没有移除。
是的,感谢指出,我去本地试了确实这样效果会好一些,我修改一下。再次感谢😄
laibao101 commented
部分逻辑做了优化处理,整体没啥变化。
window.onload = function() {
const $box = document.querySelector("#box");
$box.addEventListener("mousedown", function onMouseDown(ev) {
const { event = ev } = window;
const distanceX = event.clientX - $box.offsetLeft;
const distanceY = event.clientY - $box.offsetTop;
document.addEventListener("mousemove", onMouseMove);
function onMouseMove(eve) {
const docEvent = eve || window.event;
const left = inRange(
docEvent.clientX - distanceX,
0,
document.documentElement.clientWidth - $box.offsetWidth
);
const top = inRange(
docEvent.clientY - distanceY,
0,
document.documentElement.clientHeight - $box.offsetHeight
);
$box.style.left = `${left}px`;
$box.style.top = `${top}px`;
}
$box.addEventListener("mouseup", onMouseUp);
function onMouseUp() {
document.removeEventListener("mousemove", onMouseMove);
$box.removeEventListener("mouseup", onMouseUp);
}
});
};
function inRange(num, start, end) {
let ret = num;
ret = Math.max(ret, start);
ret = Math.min(ret, end);
return ret;
}