Javascript完美拖拽就是在網(wǎng)頁(yè)上實(shí)現(xiàn)簡(jiǎn)單的鼠標(biāo)拖拽功能,在前端開(kāi)發(fā)中非常常見(jiàn)。一個(gè)經(jīng)典的例子是實(shí)現(xiàn)一個(gè)拖動(dòng)式的用戶(hù)登錄表單,用戶(hù)可以通過(guò)鼠標(biāo)拖動(dòng)表單至網(wǎng)頁(yè)的任何地方進(jìn)行登錄。而實(shí)現(xiàn)這一功能的核心就是Javascript的拖拽特性,下面我們來(lái)詳細(xì)介紹Javascript完美拖拽的實(shí)現(xiàn)方式。
第一步,只需要監(jiān)聽(tīng)mousedown(鼠標(biāo)按下)事件,記錄元素在文檔中的位置和鼠標(biāo)在元素內(nèi)部的位置。比如下面的代碼:
elem.addEventListener('mousedown', function(e) { e.preventDefault(); x = e.clientX - elem.offsetLeft; y = e.clientY - elem.offsetTop; }, false);
第二步,監(jiān)聽(tīng)mousemove(鼠標(biāo)移動(dòng))事件,根據(jù)鼠標(biāo)移動(dòng)的距離改變?cè)卦谖臋n中的位置。比如下面的代碼:
document.addEventListener('mousemove', function(e) { if (e.target === elem) { elem.style.left = e.clientX - x + 'px'; elem.style.top = e.clientY - y + 'px'; } }, false);
第三步,當(dāng)鼠標(biāo)松開(kāi)時(shí),停止監(jiān)聽(tīng)鼠標(biāo)移動(dòng)事件。比如下面的代碼:
document.addEventListener('mouseup', function() { document.removeEventListener('mousemove', moveFn, false); }, false);
前面的代碼只是最基本的拖拽功能實(shí)現(xiàn),我們還需要對(duì)細(xì)節(jié)進(jìn)行優(yōu)化,比如防止拖拽出界、拖拽過(guò)程中禁止文字被選中等等。
對(duì)于防止拖拽出界,我們需要在移動(dòng)元素的同時(shí)判斷是否超出文檔邊界,如果超出則停止移動(dòng)。比如下面的代碼:
document.addEventListener('mousemove', function(e) { var moveX = e.clientX - x; var moveY = e.clientY - y; if (moveX< 0) { moveX = 0; } else if (moveX >document.documentElement.clientWidth - elem.offsetWidth) { moveX = document.documentElement.clientWidth - elem.offsetWidth; } if (moveY< 0) { moveY = 0; } else if (moveY >document.documentElement.clientHeight - elem.offsetHeight) { moveY = document.documentElement.clientHeight - elem.offsetHeight; } elem.style.left = moveX + 'px'; elem.style.top = moveY + 'px'; }, false);
對(duì)于禁止文字被選中,我們可以在元素mousedown時(shí)添加樣式,將樣式設(shè)置為取消選擇狀態(tài),如下所示:
elem.addEventListener('mousedown', function(e) { e.preventDefault(); x = e.clientX - elem.offsetLeft; y = e.clientY - elem.offsetTop; elem.classList.add('unselectable'); }, false); elem.addEventListener('mouseup', function() { elem.classList.remove('unselectable'); }, false);
最后,我們來(lái)實(shí)現(xiàn)完美的拖拽,即解決鼠標(biāo)移動(dòng)太快時(shí)元素跟不上鼠標(biāo)的移動(dòng)問(wèn)題。為了解決這個(gè)問(wèn)題,我們需要在mousemove事件中使用requestAnimationFrame在每幀之間重新繪制元素位置,從而使元素位置跟隨鼠標(biāo)移動(dòng)。比如下面的代碼:
var ticking = false; document.addEventListener('mousemove', function(e) { var moveX = e.clientX - x; var moveY = e.clientY - y; if (moveX< 0) { moveX = 0; } else if (moveX >document.documentElement.clientWidth - elem.offsetWidth) { moveX = document.documentElement.clientWidth - elem.offsetWidth; } if (moveY< 0) { moveY = 0; } else if (moveY >document.documentElement.clientHeight - elem.offsetHeight) { moveY = document.documentElement.clientHeight - elem.offsetHeight; } var updatePosition = function() { elem.style.left = moveX + 'px'; elem.style.top = moveY + 'px'; ticking = false; }; if (!ticking) { requestAnimationFrame(updatePosition); ticking = true; } }, false);
以上就是Javascript完美拖拽的實(shí)現(xiàn)方法和優(yōu)化技巧。當(dāng)然,實(shí)現(xiàn)拖拽的方式不止這一種,我們還可以使用jQuery UI等工具庫(kù)、CSS3的drag-and-drop等方式。無(wú)論哪種方式,掌握J(rèn)avascript的拖拽特性是必要的技能。