譯者:Flyingis

    JavaScript擅長(cháng)于修改頁(yè)面中的DOM元素,但是我們使用JavaScript通常只是實(shí)現一些簡(jiǎn)單功能,例如實(shí)現圖片的翻轉,網(wǎng)頁(yè)中的標簽頁(yè),等等。這篇文章將向你展示如何在頁(yè)面中,對創(chuàng )建的元素實(shí)現拖放。

    有許多理由讓你在頁(yè)面中加入拖放的功能,其中最簡(jiǎn)單的理由是重新組織數據。舉個(gè)例子,你可能希望用戶(hù)能夠重組一系列的頁(yè)面元素,通過(guò)放置一個(gè)input或select組件在各個(gè)元素的旁邊來(lái)代表它們的順序是一種解決方案,使該組元素可以被拖放是一種替代方案?;蛘咭苍S你想在網(wǎng)站上擁有一個(gè)可以被用戶(hù)移動(dòng)的導航窗口。這些都是使用拖放功能的簡(jiǎn)單理由,因為你能夠實(shí)現!

    在你的網(wǎng)頁(yè)上實(shí)現拖放的效果并不是很復雜。首先,我們知道鼠標的位置,然后我們需要了解用戶(hù)什么時(shí)候點(diǎn)擊一個(gè)元素,以至于我們知道要準備開(kāi)始拖動(dòng)它,最后我們要移動(dòng)這個(gè)元素。

    捕獲鼠標的移動(dòng)

    第一步,我們需要獲取鼠標的坐標,通過(guò)一個(gè)函數并賦給document.onmousemove可以實(shí)現這一功能:

document.onmousemove = mouseMove;
function mouseMove(ev) {
  ev 
= ev || window.event;
  
var mousePos = mouseCoords(ev);
}

function mouseCoords(ev) {
  
if(ev.pageX || ev.pageY) {
    
return {x:ev.pageX, y:ev.pageY};
  }

  
return {
    x:ev.clientX 
+ document.body.scrollLeft - document.body.clientLeft,
    y:ev.clientY 
+ document.body.scrollTop - document.body.clientTop
  }
;
}

    首先我們需要解釋一下event對象。不論你什么時(shí)候移動(dòng)、點(diǎn)擊鼠標,或按鍵,等等,一個(gè)事件都會(huì )發(fā)生。在IE中,這個(gè)事件是全局的,它被存儲在window.event中,對于Firefox,及其他的瀏覽器來(lái)說(shuō),這個(gè)事件將被傳遞到任何指向這個(gè)頁(yè)面動(dòng)作的函數中。因此,我們使document.onmousemove指向鼠標移動(dòng)的函數,鼠標移動(dòng)的函數獲得事件對象。

    上述代碼中,ev在所有瀏覽器環(huán)境中都包含了event對象。在Firefox里,"||window.event"將被忽略,因為它已經(jīng)包含事件。在IE中,ev的值為空,以至于需要將它的值設置為window.event。

    本文中我們需要多次捕獲到鼠標的坐標,因此我們寫(xiě)了一個(gè)mouseCoords方法,它有一個(gè)參數:event。

    我們要再次討論IE和其他瀏覽器之間的差異。Firefox和其他的瀏覽器使用event.pageX和event.pageY來(lái)表示鼠標相對于document文檔的位置。如果你有一個(gè)500*500的窗口,并且鼠標位于窗口中間,那么pageX和pageY的值將都是250。如果你將窗口向下滾動(dòng)500象素,pageY的值為750。

    如此相反的是,微軟的IE使用event.clientX和event.clientY來(lái)表示鼠標相對于window窗口的位置,而不是當前document文檔。在相同的例子中,如果將鼠標放置于500*500窗口的中間,clientX和clientY值將均為250。如果向下滾動(dòng)頁(yè)面,clientY將仍為250,因為它是相對于window窗口來(lái)測量,而不是當前的document文檔。因此,在鼠標位置中,我們應該引入document文檔body區域的scrollLeft和scrollTop屬性。最后,IE中document文檔實(shí)際并不在(0,0)的位置,在它周?chē)幸粋€(gè)?。ㄍǔS?px)邊框,document.body.clientLeft和document.body.clientTop包含了這個(gè)邊框的寬度,從而還需要在鼠標位置中引入它們。

    幸運的是,現在我們擁有了mouseCoords函數,不用再為獲取鼠標位置擔心了。

    捕獲鼠標的點(diǎn)擊
 
    下一步,我們必須知道鼠標何時(shí)點(diǎn)擊及何時(shí)釋放。如果我們跳過(guò)這一步,只要你的鼠標移動(dòng)經(jīng)過(guò)這些元素時(shí),都將產(chǎn)生拖動(dòng)這些元素的效果,這是令人討厭并違反人的直覺(jué)的。

    在這里,有兩個(gè)函數可以幫助我們:onmousedown和onmouseup。先前我們已將document.onmousemove指向一個(gè)函數,因此從邏輯上似乎應該使document.onmousedown和document.onmouseup都指向函數。如果我們讓document.onmousedown指向一個(gè)函數,那么這個(gè)函數將會(huì )因為鼠標點(diǎn)擊任何元素而執行:文本、圖像、表格,等等。我們只想頁(yè)面中特定的元素具有被拖放的功能,因此,我們可以通過(guò)如下方法實(shí)現:

document.onmouseup = mouseUp;
var dragObject = null;
function makeClickable(object) {
  object.onmousedown 
= function() {
  dragObject 
= this;
  }

}

function mouseUp(ev) {
  dragObject 
= null;
}

    我們現在有了一個(gè)變量dragObject,包含了你點(diǎn)擊的任何元素。當你釋放鼠標的時(shí)候,dragObject被設置為空,從而在dragObject非空的時(shí)候,我們需要進(jìn)行拖動(dòng)操作。

    原文鏈接:http://www.webreference.com/programming/javascript/mk/column2/index.html