面试中经常会被问到有没有做过类似模态框的拖拽行为,当时脑子里面没有一个具体的实现方向,大致思路,其实自己静下心动手实践一下也不难,了解如何去操作,实现逻辑屡清楚了基本离成功就不远了,需要注意的事,这里面涉及到很多细节问题,比如获取鼠标点击位置距离wrap的一个相对位置,wrap自身的一个宽度获取,有滚动条的时候,对于滚动距离的获取等等,这些一定要弄清楚了。
创建一个dialog类,实现一个dialog对话框,可拖拽
效果图
具体实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
| class Dialog { constructor(text) { this.x = 0; this.y = 0; this.isMoving = false; this.dialog = null; this.box = null; this.text = text || ''; this.toLeft = 0; this.toTop = 0; this.a = 1; }
open() { this.dialog = document.createElement('div'); this.dialog.style = ` width:200px; height:100px; padding:20px; background-color:#ccc; position:absolute; top:50%; left:50%; border-radius:4px;`; this.dialog.innerText = this.text; this.dialog.addEventListener('click', ev => ev.stopPropagation()); this.dialog.addEventListener('mousedown', this.handleMouseDown.bind(this)); document.addEventListener('mousemove', this.handleMouseMove.bind(this)); document.addEventListener('mouseup', this.handleMouseUp.bind(this)); document.body.appendChild(this.dialog); }
handleMouseDown(ev) { this.isMoving = true; this.box = document.createElement('div'); this.box.style = ` width:${this.dialog.offsetWidth}px; height:${this.dialog.offsetHeight}px; position:absolute; top:${this.dialog.offsetTop}px; left:${this.dialog.offsetLeft}px; border:1px dashed #000; border-radius:4px; `; document.body.appendChild(this.box); this.x = ev.offsetX; this.y = ev.offsetY;
}
handleMouseMove(ev) { if (this.isMoving) { let scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft; let scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
this.toLeft = ev.clientX + scrollLeft - this.x; this.toTop = ev.clientY + scrollTop - this.y;
let maxLeft = window.innerWidth + scrollLeft - this.dialog.offsetWidth; let maxTop = window.innerHeight + scrollTop - this.dialog.offsetHeight; if (this.toLeft < 0) { this.toLeft = 0; } else if (this.toLeft > maxLeft) { this.toLeft = maxLeft; };
if (this.toTop < 0) { this.toTop = 0; } else if (this.toTop > maxTop) { this.toTop = maxTop; };
this.box.style.left = this.toLeft + 'px'; this.box.style.top = this.toTop + 'px'; } }
handleMouseUp() { this.a += 1; this.dialog.style.left = this.toLeft + 'px'; this.dialog.style.top = this.toTop + 'px'; document.body.removeChild(this.box); document.removeEventListener('mousemove', this.handleMouseMove); document.removeEventListener('mouseup', this.handleMouseUp); this.isMoving = false; } }; let dialog = new Dialog('hello'); dialog.open();
|
这里的mousemove的监听对象修改为了document,否则如果我们拖拽速度太快会出现bug,即可能鼠标脱离了容器,然后这时就会出现问题,
只要将事件代理到了document身上就可以解决这个问题了。