【翻譯】如何在 JavaScript 中實現拖放(中)

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

    移動元素

    我們現在已經知道如何捕獲鼠標移動和點擊。接下來需要做的就是移動任何我們想拖動的元素。首先,將一個元素準確移動到頁面上我們想要的位置,該元素樣式表的position值必須爲absolute,這意味着你可以設置它的style.top或style.left,測量值相對於頁面的左上角,因爲我們所有的鼠標移動都是相對於頁面左上角的,通常都是這樣。

    一旦我們設置了item.style.position='absolute',接下來就需要改變該元素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 
=
 'absolute';
    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
;
  }

}

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

    當我們點擊一個元素時,存儲了另外的一個變量,mouseOffset。mouseOffset簡單的包含了我們點擊元素的位置信息。如果我們有一張20*20px的圖像,然後點擊圖像的中間,mouseOffset應該是{x:10, y:10}。如果我們點擊圖像的左上角,mouseOffset應爲{x:0, y:0}。我們在鼠標移動後的位置信息中用到它。如果我們沒有存儲這個值,不論你點擊元素的哪一個位置,元素相對於鼠標的位置都將會是相同的。

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

    要完成獲取元素相對於document文檔位置的工作,getPosition從它自身的父級開始,循環獲取它的left和top的值並累加,這樣我們就得到了我們想要的元素距文檔頂部和左側的累計值。

    當我們獲取了這條信息並移動鼠標的時候,mouseMove開始運行。首先我們需要保證item.style.position值爲absolute,接着,我們將元素移動到任何一個地方,鼠標位置都會減去我們之前記錄的鼠標相對於元素的偏移量。當鼠標釋放時,dragObject將被設置爲null,並且mouseMove函數不再做任何事情。

    放置元素

    我們前面的例子已經處理了這個問題,僅僅是拖動一個元素,然後將它放下。然後,在我們放下元素的時候通常還有其他的目的,我們以拖動元素到垃圾回收站爲例,或我們可能想讓該元素和頁面中某個特定的區域對齊。

    不幸的是我們在這裏進入了一個相對主要的問題。因爲我們正在移動的元素總是直接處於我們的鼠標下,而不可能去引發mouseover、mousedown、mouseup或鼠標對頁面中其他元素的操作。如果你移動一個元素到垃圾回收站,你的鼠標會一直在移動元素的上方,而不是垃圾回收站。

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

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

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

  /*
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 ;
}

    這個例子中當鼠標釋放時,我們循環每個可能放置元素的目標,如果鼠標指針在目標上,我們則擁有了一個放置元素的事件,通過鼠標橫座標大於目標元素左側橫座標(mousePos.x>targPos.x),小於目標元素右側橫座標(mousePos.x<(targPos.x+targWidth))來判定,對於Y座標我們做同樣的判斷。如果所有的這些值都返回true,那麼我們的鼠標就是在目標元素的範圍內。

發佈了30 篇原創文章 · 獲贊 4 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章