譯者: Flyingis 

    上一篇文章
介紹了移動頁面元素所涉及到的捕獲鼠標(biāo)移動和鼠標(biāo)點(diǎn)擊的相關(guān)問題,本段文章將介紹如何移動和放置頁面元素。

    移動元素

    我們現(xiàn)在已經(jīng)知道如何捕獲鼠標(biāo)移動和點(diǎn)擊。接下來需要做的就是移動任何我們想拖動的元素。首先,將一個元素準(zhǔn)確移動到頁面上我們想要的位置,該元素樣式表的position值必須為absolute,這意味著你可以設(shè)置它的style.top或style.left,測量值相對于頁面的左上角,因?yàn)槲覀兯械氖髽?biāo)移動都是相對于頁面左上角的,通常都是這樣。

    一旦我們設(shè)置了item.style.position=‘a(chǎn)bsolute‘,接下來就需要改變該元素top和left的位置,使它移動!

document.onmousemove  =
 mouseMove;
document.onmouseup   
=
 mouseUp;

var  dragObject   =   null
;
var  mouseOffset  =   null
;

function  getMouseOffset(target, ev) 
{
  ev 
=  ev  ||
 window.event;

  
var  docPos  =
 getPosition(target);
  
var  mousePos  =
 mouseCoords(ev);

   
return   {x:mousePos.x  -  docPos.x, y:mousePos.y  -  docPos.y}
;
}


function  getPosition(e)  {
  
var  left  =   0
;
  
var  top   =   0
;

  
while  (e.offsetParent)
{
    left 
+=
 e.offsetLeft;
    top 
+=
 e.offsetTop;
    e 
=
 e.offsetParent;
  }


  left 
+=  e.offsetLeft;
  top 
+=
 e.offsetTop;

  
return   {x:left, y:top}
;
}


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

  
if  (dragObject) 
{
    dragObject.style.position 
=
 ‘a(chǎn)bsolute‘;
    dragObject.style.top 
=  mousePos.y  -
 mouseOffset.y;
    dragObject.style.left 
=  mousePos.x  -
 mouseOffset.x;
    
return   false
;
  }

}


function  mouseUp()  {
  dragObject 
=   null
;
}


function  makeDraggable(item)  {
  
if  ( ! item)  return
;
  item.onmousedown 
=   function (ev) 
{
    dragObject  
=   this
;
    mouseOffset 
=  getMouseOffset( this
, ev);
    
return   false
;
  }

}

    你會注意到這些代碼是以我們前面的例子為基礎(chǔ)的(參考上篇文章),將它們放置在一起,你將能夠隨意的去移動元素。

    當(dāng)我們點(diǎn)擊一個元素時(shí),存儲了另外的一個變量,mouseOffset。mouseOffset簡單的包含了我們點(diǎn)擊元素的位置信息。如果我們有一張20*20px的圖像,然后點(diǎn)擊圖像的中間,mouseOffset應(yīng)該是{x:10, y:10}。如果我們點(diǎn)擊圖像的左上角,mouseOffset應(yīng)為{x:0, y:0}。我們在鼠標(biāo)移動后的位置信息中用到它。如果我們沒有存儲這個值,不論你點(diǎn)擊元素的哪一個位置,元素相對于鼠標(biāo)的位置都將會是相同的。

    mouseOffset函數(shù)用到了另外一個函數(shù)getPosition。getPosition目的是返回元素相對于documemt文檔的坐標(biāo)位置。如果我們簡單的去讀取item.offsetLeft或item.style.left,得到的將是元素相對于它父元素的位置,而不是document文檔的。在我們的腳本中,所有的元素都是相對于document文檔的,因此需要這樣做。

    要完成獲取元素相對于document文檔位置的工作,getPosition從它自身的父級開始,循環(huán)獲取它的left和top的值并累加,這樣我們就得到了我們想要的元素距文檔頂部和左側(cè)的累計(jì)值。

    當(dāng)我們獲取了這條信息并移動鼠標(biāo)的時(shí)候,mouseMove開始運(yùn)行。首先我們需要保證item.style.position值為absolute,接著,我們將元素移動到任何一個地方,鼠標(biāo)位置都會減去我們之前記錄的鼠標(biāo)相對于元素的偏移量。當(dāng)鼠標(biāo)釋放時(shí),dragObject將被設(shè)置為null,并且mouseMove函數(shù)不再做任何事情。

    放置元素

    我們前面的例子已經(jīng)處理了這個問題,僅僅是拖動一個元素,然后將它放下。然后,在我們放下元素的時(shí)候通常還有其他的目的,我們以拖動元素到垃圾回收站為例,或我們可能想讓該元素和頁面中某個特定的區(qū)域?qū)R。

    不幸的是我們在這里進(jìn)入了一個相對主要的問題。因?yàn)槲覀冋谝苿拥脑乜偸侵苯犹幱谖覀兊氖髽?biāo)下,而不可能去引發(fā)mouseover、mousedown、mouseup或鼠標(biāo)對頁面中其他元素的操作。如果你移動一個元素到垃圾回收站,你的鼠標(biāo)會一直在移動元素的上方,而不是垃圾回收站。

    那么我們該如何處理這個問題呢?這里有幾種解決方案。在前面所提到的mouseOffset的目的是保證元素總是在鼠標(biāo)下方正確的位置,如果你忽視了這點(diǎn),然后總是使得元素在鼠標(biāo)的右下方,你的鼠標(biāo)將不會被你正在拖動的元素所隱藏,我們也不會碰到問題。但事實(shí)上往往不會這樣,為了美觀我們通常要保持元素在鼠標(biāo)的下方。

    另外一種選擇是不移動你正在拖動的元素,你可以改變鼠標(biāo)樣式,來告訴使用者你正在拖動一個元素,直到你將它放置到某個地方。這解決了我們的問題,但是帶來了和前面一種方案面臨的同樣問題:美觀。

    我們最后的一種解決方案既不影響你正在移動的元素,也不影響移動終點(diǎn)位置上的元素(例如垃圾回收站)。不幸的是,這比前面兩種解決方案的難度更大。我們將要做的是獲得一組我們要放置的目標(biāo),當(dāng)鼠標(biāo)釋放時(shí),我們手工檢查當(dāng)前鼠標(biāo)相對于每個目標(biāo)的位置,看鼠標(biāo)是否釋放在這個目標(biāo)中某一個目標(biāo)的位置上,如果是的,我們就知道我們已經(jīng)將元素放置在我們的目標(biāo)上了。

/*
All code from the previous example is needed with the exception
of the mouseUp function which is replaced below
*/


var  dropTargets  =  [];

function  addDropTarget(dropTarget) 
{
  dropTargets.push(dropTarget);
}


function  mouseUp(ev)  {
  ev 
=  ev  ||
 window.event;
  
var  mousePos  =
 mouseCoords(ev);

  
for  ( var  i = 0 ; i < dropTargets.length; i ++
{
    
var  curTarget  =
 dropTargets[i];
    
var  targPos  =
 getPosition(curTarget);
    
var  targWidth  =
 parseInt(curTarget.offsetWidth);
    
var  targHeight  =
 parseInt(curTarget.offsetHeight);

    
if
 (
      (mousePos.x 
>  targPos.x)  &&
 
      (mousePos.x 
<  (targPos.x  +  targWidth))  &&
 
      (mousePos.y 
>  targPos.y)  &&
 
      (mousePos.y 
<  (targPos.y  +  targHeight))) 
{
      
//  dragObject was dropped onto curTarget!

      }

  }


  dragObject   
=   null ;
}

    這個例子中當(dāng)鼠標(biāo)釋放時(shí),我們循環(huán)每個可能放置元素的目標(biāo),如果鼠標(biāo)指針在目標(biāo)上,我們則擁有了一個放置元素的事件,通過鼠標(biāo)橫坐標(biāo)大于目標(biāo)元素左側(cè)橫坐標(biāo)(mousePos.x>targPos.x),小于目標(biāo)元素右側(cè)橫坐標(biāo)(mousePos.x<(targPos.x+targWidth))來判定,對于Y坐標(biāo)我們做同樣的判斷。如果所有的這些值都返回true,那么我們的鼠標(biāo)就是在目標(biāo)元素的范圍內(nèi)。

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

    另外兩篇:[翻譯] 如何在 JavaScript 中實(shí)現(xiàn)拖放(上)   [翻譯] 如何在 JavaScript 中實(shí)現(xiàn)拖放(下)