原来这样可以实现鼠标拖拽
引言: 上次弄了图片放大镜效果(图片放大镜原来是这么回事),当时用到了clientX clientY 后来查询了一下这两个属性,发现居原来还可以用来做简单的拖拽。实现原理与放大镜那里一样,改变left 与top 的数值让 div 移动。
1 #box{ 2 width: 100px; 3 height: 100px; 4 border: 1px solid red ; 5 background: rgba(24,41,254,0.71); 6 position: absolute;/* 使用绝对定位或者相对定位,使left和top起效达到移动效果。不过用绝对定位可以脱离文档流不影响布局。*/ 7 /*z-index: 9999;*/ 8 } 9 #box2{ 10 width: 100px; 11 height: 100px; 12 border: 2px darkcyan dashed; 13 background: rgba(84,254,80,0.71); 14 left: 200px; 15 position: relative; 16 top: 100px; 17 } 18 </style> 19 <body> 20 <div id="box"> 21 22 </div> 23 <div id="box2"> 24 25 </div> 26 27 <script> 28 var box=document.getElementById("box"); 29 30 box.onmousedown=function () { // 鼠标按下触发事件 31 32 document.onmousemove=function (event) { // 鼠标移动时获取焦点坐标,并赋予给box ,至于为什么用document不用box,我试过box,拖拽过快会出现box跟不上, 33 34 var event=event||window.event 35 36 var left=event.clientX; // 获取鼠标焦点坐标 37 var top=event.clientY; 38 39 box.style.left=left+'px'; // 焦点赋予给left 改变box 的left 已达到移动 40 box.style.top=top+'px'; 41 42 /* box.style.width=left+'px';// 使用这个还可以改变 box 的大小哦。。。。 43 box.style.height=top+'px';*/ 44 }; 45 document.onmouseup=function () { // 鼠标放开后停止移动 46 document.onmousemove=null; 47 document.onmouseup=null; 48 } 49 }
ps: demo 演示平台又挂了,暂时不能演示demo 效果。
--------------------------------------------------------------------2018-9-27更新补充-----------------------------------------------------------------
上面的拖拽虽然成功了,但是却有一个问题,那就是
var left=event.clientX; // 获取鼠标焦点坐标
var top=event.clientY; box.style.left=left+'px'; // 焦点赋予给left 改变box 的left 已达到移动 box.style.top=top+'px';
这里的意思是获取鼠标的焦点的 X Y坐标,然后将其赋值给 box 这个拖动块,所以就会造成一个问题,例如:当我们点击box 中间进行拖动时,鼠标焦点并不会停留在box 中间的点击位置,而是出现在右上角。就像这样:
(图 ——1)
所以为了避免这样糟糕的拖拽体验。我们要计算box 拖拽块的移动距离,也就是当鼠标点击块中间时,box 需要移动到鼠标点击的位置,这样在后面的跟随中就不会让自己的右上角变成鼠标的点击位置了。看图:
(L表示left . T表示top):红线+绿线=焦点到边距的距离。假如此时我们拖拽box ,鼠标焦点会从中间跑到右上角如 图——1 那样,那么为了让鼠标保持在中间位置,我们需要让box 移动 绿线这么长的距离,而绿线距离等于焦点到边距的距离(红+绿)-红(box到边框的距离)=绿线。
而如何获取红+绿的距离呢?上面代码中 event.clientX 就可以了,而红线的距离可以使用 event.clientX-box.getBoundingClientRect().left; 这个 getBoundingClientRect().left / top 可以获取box 到边距的距离,当然这里也可以使用 offset 来获取,二者区别是 如果有父级元素,且父级元素定位的话,offset
获取的距离就是边框到父级元素的距离,如果父元素不是定位元素,那么子元素的offset值相对于 可视区窗口。而 getBoundingClientRect() 的值只相对于可视去窗口。
直接上更新后的代码:
1 <style> 2 #box{ 3 width: 100px; 4 height: 100px; 5 border: 1px solid red ; 6 background: rgba(24,41,254,0.71); 7 position: absolute;/* 使用绝对定位或者相对定位,使left和top起效达到移动效果。不过用绝对定位可以脱离文档流不影响布局。*/ 8 /*z-index: 9999;*/ 9 } 10 #box2{ 11 width: 100px; 12 height: 100px; 13 border: 2px darkcyan dashed; 14 background: rgba(84,254,80,0.71); 15 left: 200px; 16 position: relative; 17 top: 100px; 18 } 19 </style> 20 <body> 21 拖拽测试 22 <div id="box"> 23 拖动块 24 </div> 25 <div id="box2"> 26 固定块 27 </div> 28 29 <script> 30 var box=document.getElementById("box"); 31 32 box.onmousedown=function (event) { // 鼠标按下触发事件 33 var event=event||window.event 34 35 var bf=event.clientX-box.getBoundingClientRect().left; 36 var bp=event.clientY-box.getBoundingClientRect().top; 37 38 box.setCapture && box.setCapture(); // 阻止鼠标全选影响拖拽的方法,此为了兼容IE8,别的浏览器不支持 setCapture 属性,所以要在这里做浏览器判断,先判断是否支持此属性 39 40 41 42 document.onmousemove=function (event) { // 鼠标移动时获取焦点坐标,并赋予给box ,至于为什么用document不用box,我试过box,拖拽过快会出现box跟不上, 43 44 var event=event||window.event 45 46 var left=event.clientX-bf; // 获取鼠标焦点坐标 47 var top=event.clientY-bp; 48 49 box.style.left=left+'px'; // 焦点赋予给left 改变box 的left 已达到移动 50 box.style.top=top+'px'; 51 52 /* box.style.width=left+'px';// 还可以改变box 的大小。。。。 53 box.style.height=top+'px';*/ 54 }; 55 document.onmouseup=function () { // 鼠标放开后停止移动 56 document.onmousemove=null; 57 document.onmouseup=null; 58 59 box.releaseCapture&&box.releaseCapture() // 去除 setCapture,防止反复触发该属性,兼容IE8,也只有IE 支持所以这里也要判断
60
61 }
62
63 return false;// 浏览器全选时影响拖拽,此时用这个可以阻止
64 }
65
66
67 </script>
68 </body>
补充 上面的 提到的 :return false;// 浏览器全选时影响拖拽,此时用这个可以阻止
以及 : box.setCapture && box.setCapture(); // 阻止鼠标全选影响拖拽的方法,此为了兼容IE8,别的浏览器不支持 setCapture 属性,所以要在这里做浏览器判断,先判断是否支持此属性
如果不加,这个就会导致下面这种情况,当全选时,拖动移动框会影响周边元素的影子一起动,加了上面的代码声明可以阻止浏览器的行为,阻止下面情况发生: