javascript動(dòng)畫(huà)之模擬拖拽效果篇
先看看實(shí)現(xiàn)效果圖, 模擬拖拽最終效果和在桌面上移動(dòng)文件夾的效果類似

原理介紹
鼠標(biāo)按下時(shí),拖拽開(kāi)始。鼠標(biāo)移動(dòng)時(shí),被拖拽元素跟著鼠標(biāo)一起移動(dòng)。鼠標(biāo)抬起時(shí),拖拽結(jié)束
所以,拖拽的重點(diǎn)是確定被拖拽元素是如何移動(dòng)的

假設(shè),鼠標(biāo)按下時(shí),鼠標(biāo)對(duì)象的clientX和clientY分別為x1和x2。元素距離視口左上角x軸和y軸分別為x0和y0
鼠標(biāo)移動(dòng)的某一時(shí)刻,clientX和clientY分別為x2和y2
所以,元素移動(dòng)的x軸和y軸距離分別為x2-x1和y2-y1
元素移動(dòng)后,元素距離視口左上角x軸和y軸的位置分別為
X = x0 + (x2-x1) Y = y0 + (y2-y1)
代碼實(shí)現(xiàn)
將上面的原理用代碼實(shí)現(xiàn)如下
鼠標(biāo)按下時(shí),初始態(tài)的x0和y0分別用offsetLeft和offsetTop表示
鼠標(biāo)移動(dòng)時(shí),瞬時(shí)態(tài)的x和y分別賦值為定位后元素的left和top
<div id="test" style="height: 100px;width: 100px;background:pink;position:absolute;top:0;left:0;"></div>
<script>
test.onmousedown = function(e){
e = e || event;
//獲取元素距離定位父級(jí)的x軸及y軸距離
var x0 = this.offsetLeft;
var y0 = this.offsetTop;
//獲取此時(shí)鼠標(biāo)距離視口左上角的x軸及y軸距離
var x1 = e.clientX;
var y1 = e.clientY;
test.onmousemove = function(e){
e = e || event;
//獲取此時(shí)鼠標(biāo)距離視口左上角的x軸及y軸距離
x2 = e.clientX;
y2 = e.clientY;
//計(jì)算此時(shí)元素應(yīng)該距離視口左上角的x軸及y軸距離
var X = x0 + (x2 - x1);
var Y = y0 + (y2 - y1);
//將X和Y的值賦給left和top,使元素移動(dòng)到相應(yīng)位置
test.style.left = X + 'px';
test.style.top = Y + 'px';
}
test.onmouseup = function(e){
//當(dāng)鼠標(biāo)抬起時(shí),拖拽結(jié)束,則將onmousemove賦值為null即可
test.onmousemove = null;
}
}
</script>

代碼優(yōu)化
使用上面的代碼時(shí),會(huì)出現(xiàn)一個(gè)問(wèn)題。當(dāng)鼠標(biāo)拖動(dòng)的太快,比onmousemove事件的觸發(fā)間隔還要快時(shí),鼠標(biāo)就會(huì)從元素上離開(kāi)。這樣就停止了元素的拖拽過(guò)程
此時(shí),如果把mousemove和mouseup事件都加在document上時(shí),即可解決
<div id="test" style="height: 100px;width: 100px;background:pink;position:absolute;top:0;left:0;"></div>
<script>
test.onmousedown = function(e){
e = e || event;
//獲取元素距離定位父級(jí)的x軸及y軸距離
var x0 = this.offsetLeft;
var y0 = this.offsetTop;
//獲取此時(shí)鼠標(biāo)距離視口左上角的x軸及y軸距離
var x1 = e.clientX;
var y1 = e.clientY;
document.onmousemove = function(e){
e = e || event;
//獲取此時(shí)鼠標(biāo)距離視口左上角的x軸及y軸距離
x2 = e.clientX;
y2 = e.clientY;
//計(jì)算此時(shí)元素應(yīng)該距離視口左上角的x軸及y軸距離
var X = x0 + (x2 - x1);
var Y = y0 + (y2 - y1);
//將X和Y的值賦給left和top,使元素移動(dòng)到相應(yīng)位置
test.style.left = X + 'px';
test.style.top = Y + 'px';
}
document.onmouseup = function(e){
//當(dāng)鼠標(biāo)抬起時(shí),拖拽結(jié)束,則將onmousemove賦值為null即可
document.onmousemove = null;
}
}
</script>

拖拽沖突
由于文字和圖片默認(rèn)支持原生拖放,如果將原生拖放和模擬拖拽摻雜在一起,將造成與預(yù)想效果不符的情況
如果拖放的元素內(nèi)容存在文字,且文字被選中會(huì)觸發(fā)文字的原生拖放效果
在文字上面雙擊鼠標(biāo),即可選中文字,再移動(dòng)鼠標(biāo)時(shí),會(huì)觸發(fā)文字的原生拖放效果,如下所示

只要在onmousedown事件阻止瀏覽器的默認(rèn)行為即可
<div id="test" style="height: 100px;width: 100px;background:pink;position:absolute;top:0;left:0;">測(cè)試文字</div>
<script>
test.onmousedown = function(e){
e = e || event;
//獲取元素距離定位父級(jí)的x軸及y軸距離
var x0 = this.offsetLeft;
var y0 = this.offsetTop;
//獲取此時(shí)鼠標(biāo)距離視口左上角的x軸及y軸距離
var x1 = e.clientX;
var y1 = e.clientY;
document.onmousemove = function(e){
e = e || event;
//獲取此時(shí)鼠標(biāo)距離視口左上角的x軸及y軸距離
x2 = e.clientX;
y2 = e.clientY;
//計(jì)算此時(shí)元素應(yīng)該距離視口左上角的x軸及y軸距離
var X = x0 + (x2 - x1);
var Y = y0 + (y2 - y1);
//將X和Y的值賦給left和top,使元素移動(dòng)到相應(yīng)位置
test.style.left = X + 'px';
test.style.top = Y + 'px';
}
document.onmouseup = function(e){
//當(dāng)鼠標(biāo)抬起時(shí),拖拽結(jié)束,則將onmousemove賦值為null即可
document.onmousemove = null;
}
//阻止默認(rèn)行為
return false;
}
</script>
IE兼容
以上代碼在IE8-瀏覽器中仍然無(wú)法阻止默認(rèn)行為。此時(shí),為了實(shí)現(xiàn)IE兼容,需要使用全局捕獲setCapture()和釋放捕獲releaseCapture()
首先,先看一下全局捕獲的效果
下面代碼中,開(kāi)啟全局捕獲之后,頁(yè)面中的所有點(diǎn)擊效果,都相當(dāng)于針對(duì)按鈕一的點(diǎn)擊效果。釋放捕獲后,效果消失
[注意]IE瀏覽器完全支持全局捕獲;chrome不支持,使用全局捕獲會(huì)報(bào)錯(cuò);firefox不報(bào)錯(cuò),但靜默失敗
<button id="btn1">按鈕一</button>
<button id="btn2">開(kāi)啟按鈕一的全局捕獲</button>
<script>
btn1.onclick = function(){
alert(1);
}
btn2.onclick = function(){
if(btn1.setCapture){
if(btn2.innerHTML.charAt(0) == '開(kāi)'){
btn1.setCapture();
btn2.innerHTML = '關(guān)閉按鈕一的全局捕獲';
}else{
btn1.releaseCapture();
btn2.innerHTML = '開(kāi)啟按鈕一的全局捕獲';
}
}
}
</script>
通過(guò)在IE瀏覽器設(shè)置全局捕獲來(lái)達(dá)到取消文字原生拖放的默認(rèn)行為
<div id="test" style="height: 100px;width: 100px;background:pink;position:absolute;top:0;left:0;">測(cè)試文字</div>
<script>
test.onmousedown = function(e){
e = e || event;
//獲取元素距離定位父級(jí)的x軸及y軸距離
var x0 = this.offsetLeft;
var y0 = this.offsetTop;
//獲取此時(shí)鼠標(biāo)距離視口左上角的x軸及y軸距離
var x1 = e.clientX;
var y1 = e.clientY;
document.onmousemove = function(e){
e = e || event;
//獲取此時(shí)鼠標(biāo)距離視口左上角的x軸及y軸距離
x2 = e.clientX;
y2 = e.clientY;
//計(jì)算此時(shí)元素應(yīng)該距離視口左上角的x軸及y軸距離
var X = x0 + (x2 - x1);
var Y = y0 + (y2 - y1);
//將X和Y的值賦給left和top,使元素移動(dòng)到相應(yīng)位置
test.style.left = X + 'px';
test.style.top = Y + 'px';
}
document.onmouseup = function(e){
//當(dāng)鼠標(biāo)抬起時(shí),拖拽結(jié)束,則將onmousemove賦值為null即可
document.onmousemove = null;
//釋放全局捕獲
if(test.releaseCapture){
test.releaseCapture();
}
}
//阻止默認(rèn)行為
return false;
//IE8-瀏覽器阻止默認(rèn)行為
if(test.setCapture){
test.setCapture();
}
}
</script>

總結(jié)
以上就是Javascript模擬拖拽的全部?jī)?nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,如果有疑問(wèn)大家可以留言交流。
- js彈性勢(shì)能動(dòng)畫(huà)之拋物線運(yùn)動(dòng)實(shí)例詳解
- 原生javascript實(shí)現(xiàn)勻速運(yùn)動(dòng)動(dòng)畫(huà)效果
- js運(yùn)動(dòng)動(dòng)畫(huà)的八個(gè)知識(shí)點(diǎn)
- JS運(yùn)動(dòng)框架之分享側(cè)邊欄動(dòng)畫(huà)實(shí)例
- javascript動(dòng)畫(huà)之圓形運(yùn)動(dòng),環(huán)繞鼠標(biāo)運(yùn)動(dòng)作小球
- 用js實(shí)現(xiàn)的模擬jquery的animate自定義動(dòng)畫(huà)(2.5K)
- 用js模擬JQuery的show與hide動(dòng)畫(huà)函數(shù)代碼
- js 排序動(dòng)畫(huà)模擬 冒泡排序
- JS實(shí)現(xiàn)基于Sketch.js模擬成群游動(dòng)的蝌蚪運(yùn)動(dòng)動(dòng)畫(huà)效果【附demo源碼下載】
相關(guān)文章
js 顯示日期時(shí)間的實(shí)例(時(shí)間過(guò)一秒加1)
下面小編就為大家?guī)?lái)一篇js 顯示日期時(shí)間的實(shí)例(時(shí)間過(guò)一秒加1)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-10-10
基于原生JavaScript實(shí)現(xiàn)SPA單頁(yè)應(yīng)用
單頁(yè)Web應(yīng)用?(single?page?web?application,SPA)?,就是只有一張Web頁(yè)面的應(yīng)用,是加載單個(gè)HTML?頁(yè)面并在用戶與應(yīng)用程序交互時(shí)動(dòng)態(tài)更新該頁(yè)面的Web應(yīng)用程序。本文將利用原生JS實(shí)現(xiàn)SPA單頁(yè)應(yīng)用,需要的可以參考一下2023-03-03
JavaScript中Function函數(shù)與Object對(duì)象的關(guān)系
這篇文章主要介紹了JavaScript中Function函數(shù)與Object對(duì)象的關(guān)系的相關(guān)資料,需要的朋友可以參考下2015-12-12
JavaScript實(shí)現(xiàn)字符串截取的三個(gè)方法總結(jié)
在?JavaScript?中,可以使用?substr()、slice()?和?substring()?方法截取字符串。這篇文章就來(lái)通過(guò)一些示例和大家聊聊這些方法的具體操作,需要的可以參考一下2023-02-02
基于JavaScript實(shí)現(xiàn)網(wǎng)頁(yè)計(jì)算器
這篇文章主要為大家詳細(xì)介紹了基于JavaScript實(shí)現(xiàn)網(wǎng)頁(yè)計(jì)算器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-05-05
js百度地圖滾輪縮放所在點(diǎn)偏移問(wèn)題解決
本文主要介紹了js百度地圖滾輪縮放所在點(diǎn)偏移問(wèn)題解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-02-02
javascript DIV實(shí)現(xiàn)跟隨鼠標(biāo)移動(dòng)
這篇文章主要為大家詳細(xì)介紹了javascript DIV跟隨鼠標(biāo)移動(dòng),有一個(gè)div跟隨鼠標(biāo)移動(dòng)的結(jié)果,有一連串跟隨鼠標(biāo)移動(dòng)的效果,感興趣的小伙伴們可以參考一下2016-02-02
js實(shí)現(xiàn)鼠標(biāo)滾輪控制圖片縮放效果的方法
這篇文章主要介紹了js實(shí)現(xiàn)鼠標(biāo)滾輪控制圖片縮放效果的方法,涉及onmousewheel事件及javascript操作圖片的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-02-02

