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)文章
JavaScript Tips 使用DocumentFragment加快DOM渲染速度
大家在開(kāi)發(fā)JavaScript應(yīng)用的時(shí)候,如果遇到這種大量節(jié)點(diǎn)的情況,不妨將DocumentFragment作為一個(gè)備選的方案。2010-06-06用javascript實(shí)現(xiàn)div可編輯的常見(jiàn)方法
用javascript實(shí)現(xiàn)div可編輯的常見(jiàn)方法...2007-10-10再談JavaScript中bind、call、apply三個(gè)方法的區(qū)別與使用方式
這篇文章主要介紹了Javascript中bind、call、apply三個(gè)方法的使用方式,需要的朋友可以參考下2022-05-05js獲取select標(biāo)簽的值且兼容IE與firefox
本篇文章主要介紹了js獲取select標(biāo)簽的值且兼容IE與firefox。需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助2013-12-12css值轉(zhuǎn)換成數(shù)值請(qǐng)拋棄parseInt
絕大多數(shù)人喜歡用parseInt()把css中的字符串值轉(zhuǎn)換成數(shù)值2011-10-10移動(dòng)端H5開(kāi)發(fā) Turn.js實(shí)現(xiàn)很棒的翻書(shū)效果
這篇文章主要為大家詳細(xì)介紹了Turn.js實(shí)現(xiàn)很棒的翻書(shū)效果,對(duì)Turn.js翻書(shū)效果的實(shí)現(xiàn)進(jìn)行總結(jié),感興趣的小伙伴們可以參考一下2016-06-06純js實(shí)現(xiàn)仿QQ郵箱彈出確認(rèn)框
仿QQ郵箱的彈出層,彈出確認(rèn)框,主要是用火狐的firebug把html和css扣了下來(lái),沒(méi)有做封裝,就定義了一個(gè)拖動(dòng)事件. 大家可以封裝自己的彈出窗,嘿嘿!2015-04-04javascript獲取以及設(shè)置光標(biāo)位置
本文介紹了javascript獲取以及設(shè)置光標(biāo)位置的方法,具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧2017-02-02