1、實現的效果是在限制範圍內拖拽div+吸附+事件捕獲。html
這裏須要理解的是事件捕獲,這個事件捕獲也是爲了兼容div在拖拽過程當中,文本不被選中這個問題。chrome
如此良辰美景,拖拽也能夠很灑脫哈。先看看圖,瀏覽器
2、一步步的實現這個拖拽過程的幾個要求ide
(一)拖拽起來優化
裏面的邊框是表示頁面哦(咱們的屏幕所能看到的東東)。this
獲取移動距離的思路:spa
記錄鼠標按下和鼠標擡起兩次的座標,而後相減,再加上div跟邊緣之間的間距。就獲得移動距離。code
以前我也在這裏困惑了,不明白爲何還要再加上offsetLeft。緣由就是clientX獲取到的是數值是不加上div跟邊緣的距離,不是marin,也不是padding,而是瀏覽器渲染的問題。htm
[下面是我本身的理解:對象
終於明白這個移動距離是如何計算出來的:
將式子化簡以後,獲得的就是移動後的Div clientX-移動前clientX,而後再加上offsetLeft,由於這個clientX是沒有把邊緣計算下去,爲了獲取準確的數值,要把瀏覽器默認的邊緣計算下去。
如圖因此:鼠標移動過的距離就是我用紅色畫出部分再加上div跟邊緣之間的offsetLeft(X軸方向)和offsetTop(Y軸方向)。
若是上面式子很差理解,就把他化簡以後來看,就明白了。]
距離獲取完成。
如今就能夠經過鼠標的三個事件onmousedown、onmousemove、onmouseup來拖拽鼠標。當鼠標移動時,就不斷地更改div的left和top屬性
oDiv2.style.left = l +'px';
Div2.style.top = t +'px';
最後,當鼠標擡起時,要釋放onmousedown和onmousemove事件。
this.onmousedown = null;
this.onmousemove = null;
(二)邊緣吸附
邊緣吸附的原理so easy。
給一個判斷條件,當div運動到距離上下左右邊緣的距離小於某一個值時,這時就把left和top的值更改成邊緣的值。這樣div就貼到邊緣上去。
var l1= oDiv1.offsetWidth - oDiv2.offsetWidth; //限制小div在大div中拖拽,計算能拖拽的max距離 var t1 = oDiv1.offsetHeight - oDiv2.offsetHeight; if(l > l1-50) { l = l1; } if(l < 50) { l = 0; } if(t > t1-50) { t = t1; } if(t < 50) { t = 0; }
(三)拖拽過程不被文字選中
div在拖拽過程當中,在div中的文本文字老是會被選中,爲了解決這個問題,要使用一個叫作事件捕獲的知識。
一、先理解一下什麼是事件捕獲
是跟事件冒泡相反的一種模型。事件捕獲的是最後得到事件的是最小的子元素。事件冒泡最後得到事件的是父元素。
之因此在拖拽過程當中,div中的文字會被選中就是由於我沒有處理好事件冒泡的問題。要解決這個問題,解鈴還須繫鈴人,就把事件冒泡的問題處理很久ok。
if(oDiv2.setCapture) //IE
{
document.onmousemove = moveFn;
document.onmouseup = upFn;
oDiv2.setCapture(); //事件捕獲後,全部事件都集中到這個div
return false; //FF、Chrome、IE9
}else //FF、chrome
{
document.onmousemove = moveFn; //!!!!根源所在,在優化版1中,設置爲oDiv2.onmousemove時拖拽一次後沒法再拖拽
document.onmouseup = upFn;
}
記得事件捕獲後,當鼠標擡起時,也好釋放
oDiv2.releaseCapture();
3、div拖拽的詳細代碼
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>限制範圍內拖拽</title> <style> * { margin: 0; padding: 0; } #div1 { width: 500px; height: 500px; background: #CCC; position: relative; } #div2 { width: 100px; height: 100px; background: green; position: absolute; left: 0; top: 0; } </style> <script> window.onload = function() { var oDiv1 = document.getElementById('div1'); var oDiv2 = document.getElementById('div2'); var disX,disY; /*--------------開始拖拽div2-----------------*/ oDiv2.onmousedown = function(evt) //oDiv2.onmousedown表示按下這個對象,, document.onmouseup整個文檔對象(這裏把div改爲document是防止弄丟div) { var oEvent = evt || window.event; //evt兼容FF/Chrome disX = oEvent.clientX - oDiv2.offsetLeft; //-oDiv2.offsetLeft的距離是爲了減去div與視口邊框的距離 disY = oEvent.clientY - oDiv2.offsetTop; if(oDiv2.setCapture) //IE { document.onmousemove = moveFn; document.onmouseup = upFn; oDiv2.setCapture(); //事件捕獲後,全部事件都集中到這個div return false; //FF、Chrome、IE9 }else //FF、chrome { document.onmousemove = moveFn; //!!!!根源所在,在優化版1中,設置爲oDiv2.onmousemove時拖拽一次後沒法再拖拽 document.onmouseup = upFn; } function moveFn(evt) //把document從新改成div,利用setCapture事件捕獲,把事件都集中在一個物體上 { var oEvent = evt || window.event; var l = oEvent.clientX - disX; //計算鼠標移過的距離 var t = oEvent.clientY - disY; var l1= oDiv1.offsetWidth - oDiv2.offsetWidth; //限制小div在大div中拖拽,計算能拖拽的max距離 var t1 = oDiv1.offsetHeight - oDiv2.offsetHeight; if(l > l1-50) { l = l1; } if(l < 50) { l = 0; } if(t > t1-50) { t = t1; } if(t < 50) { t = 0; } oDiv2.style.left = l +'px'; oDiv2.style.top = t +'px'; } function upFn() { this.onmousedown = null; this.onmousemove = null; if(oDiv2.releaseCapture) //若是事件捕獲存在,則釋放事件捕獲 { oDiv2.releaseCapture(); } } return false; //阻止瀏覽器默認事件 }; }; </script> </head> <body> <div id="div1">使用了事件捕獲後,如今拖拽div中的問題可不該該被選中了哦</div> <div id="div2">helloworld helloworld</div> </body> </html>
[題外話:優化版拖拽再次沒法拖拽(已解決:緣由是document和oDiv2.onmousemove的問題)]