要求:
写一个drag类,实现鼠标在窗口工具条上可以在页面上拖动矩形窗口,并能合理控制矩形窗口的拖动边界或拖动范围。
拆解
- html
<body>
<div id="dragContainer">
<div id="dragBar"></div>
</div>
<iframe></iframe>
</body>
- css
iframe {
border: none;
height: 100vh;
width: 100vw;
}
#dragContainer {
position: absolute;
top: 0px;
left: 0px;
width: 400px;
height: 300px;
background-color: #fff;
box-shadow: 5px 5px 10px #ccc;
border:1px solid #eee
}
#dragBar {
width: 400px;
height: 40px;
background-color: #036087;
}
- 此时,页面展示如图
实现可拖拽类
- 首先初始化构造函数,定义拖拽会用到的参数,dragBar 为拖拽的控制按钮,DragContainer则为要拖拽的盒子。
- 定义一个初始化位置和拖拽完成时的位置,用来计算拖拽结束时,dragContainer的位置,以及必不可以的拖拽方法。
class Drag{
constructor(el) {
this.el = el;
this.dragDiv = el.parentNode;
this.startPosition = {};//鼠标初始位置
this.endPosition = {};//鼠标结束位置
this.initPosition={}//dragDiv初始位置
this.dragStart();
}
dragStart(){
}
}
3.首先我们先完成对点击鼠标和松开鼠标的动作进行监听,通过计算鼠标松开时的位置,和起始位置的结果,来判断dragDiv需要移动的距离
this.el.addEventListener('mousedonw',()=>{
this.el.addEventListener("mousedown", (e) => {
this.initPosition = {
x: this.dragDiv.offsetLeft,
y: this.dragDiv.offsetTop,
};
this.startPosition = {
x: e.clientX,
y: e.clientY,
};
});
})
this.el.addEventListener('mouseup',()=>{
this.el.addEventListener("mousedown", (e) => {
this.endPosition = {
x: e.clientX,
y: e.clientY,
};
const { x, y } = this.calculatePosition();
this.drag()
});
})
drag() {
const { x, y } = this.calculatePosition();
this.elDiv.style.left = this.initPosition.x + x + "px";
this.elDiv.style.top = this.initPosition.y + y + "px";
}
calculatePosition() {
const x = this.endPosition.x - this.startPosition.x;
const y = this.endPosition.y - this.startPosition.y;
return { x, y };
}
- 接下来就是拖拽时,也就是对mousemove的监听
this.el.addEventListener("mousemove", (e) => {
this.endPosition = {
x: e.clientX,
y: e.clientY,
};
this.drag();
});
- 到这一步发现,当松开鼠标时,弹窗还是会移动。因为只添加对mousemove的监听,当我们松开时,要移除对mousemove的监听,如果使用removeListner的方法,需要两个监听器时使用的参数完全一致,包括内存中回调的相同引用,所以需要将回调函数声明为一个变量,再进行调用。
const dragMove=(event) => {
this.dragMove(event);
};
this.el.addEventListener("mousemove", dragMove);
this.el.addEventListener("mouseup", () => {
this.el.removeEventListener("mousemove", dragMove);
});
- 为了解决这个麻烦的问题,我们可以使用AbortController() 来做监听的移除。
const controller = new AbortController();
const { signal } = controller;
this.el.addEventListener(
"mousemove",
(e) => {
this.endPosition = {
x: e.clientX,
y: e.clientY,
};
this.drag();
},
{ signal }
);
// 监听松开鼠标,取消对mousemove的监听
document.addEventListener("mouseup", (e) => {
this.endPosition = {
x: e.clientX,
y: e.clientY,
};
this.drag();
controller.abort();
});
总结
监听mousedown mouseup mousemove三个事件,且记录下初始位置和结束位置,对要拖拽的盒子进行控制,当松开鼠标时,清除对鼠标移动时的监听函数,当然最后还要对拖拽盒子的边界位置进行判断,使其不超出可视区。