天天看點

拖放效果系列 三

上一節我們讓拖拽代碼使用起來更友善、适用于多個元素,同時解決了偶爾會出現的拖動一個元素,多個元素一起移動的問題。但是在快速拖拽的時候,會出現延遲,或者元素幹脆就停止移動了。

元素停止移動的原因

分析一下上面問題的原因:滑鼠滑動地太快,自然會造成mousemove事件多次發生,相應的,事件處理函數也多次被調用,自然造成延遲。延遲之後,元素移動的速度趕不上滑鼠移動的速度,可能造成滑鼠移出元素的狀态,進而觸發了mouseout事件,進而造成了被拖動元素停止移動。

為了驗證上面的想法,我們給元素添加一個onmouseout的響應函數,來顯示一段字元串。修改代碼如下:

Javascript代碼

  1. <script type="text/javascript">  
  2. function dragInit(node){  
  3.     if(node.className == "drag"){   
  4.         ……  
  5.         node.onmouseout = out;  
  6.         ……  
  7.     }  
  8.         ……  
  9. }  
  10. ……  
  11. function out(){  
  12.     alert("滑鼠一出去啦,我不能再移動啦!!");  
  13. }  
  14. ……  
  15. </script>  
<script type="text/javascript">
function dragInit(node){
	if(node.className == "drag"){ 
		……
		node.onmouseout = out;
		……
	}
		……
}
……
function out(){
	alert("滑鼠一出去啦,我不能再移動啦!!");
}
……
</script>
           

點選進入測試頁面,可以發現浏覽器對mouseout十分敏感,我在IE和FF下做了測試,隻要稍微移動的快一點,就會觸發滑鼠移出事件。但是隻要在視覺上滑鼠還沒有移出元素,那麼元素還是可以正常移動的。但是如果滑鼠“看起來”移出了元素,那麼拖拽效果就真的徹底被破壞了。

解決快速拖拽時元素停止移動的問題

這個問題是不可避免的嗎?當然不是,如果你是豆瓣的使用者,可以進入“我的豆瓣”欄目測試一下它們的拖拽功能()。就算拖拽的速度再快也不會出現“突然停止”的情況。

我們也來試着解決這個問題。上面已經分析了,造成元素停止移動的原因是滑鼠移出了被拖拽的元素,造成mousemove事件無法得到響應。那麼我們讓 mousemove事件在有延遲的情況下仍然可以被響應就可以了,我們隻要把事件處理函數加到document上就可以做到這一點了(之前也想過其它解決方案,但是失敗了)。修改之後的代碼如下:

Javascript代碼

  1. <script type="text/javascript">  
  2. //使用該變量辨別拖拽的元素  
  3. var dragElement = null;  
  4. ……  
  5. function dragInit(node){  
  6.     if(node.className == "drag"){   
  7.         node.onmousedown = down;  
  8.         //使用document響應mousemove事件  
  9.         document.onmousemove = move;  
  10.         node.onmouseover = over;  
  11.         //删除該函數node.onmouseup = up;  
  12.         node.style.position = "relative";  
  13.         node.style.top = "0px";  
  14.         node.style.left = "0px";  
  15.         node.dragging = false;  
  16.     }  
  17.     var children = node.childNodes;  
  18.     for(var i = 0;i < children.length; i++){  
  19.         dragInit(children[i]);  
  20.     }  
  21. }  
  22. function down(event)  
  23. {     
  24. ……  
  25. }  
  26. function move(event){  
  27.     event = event || window.event;  
  28.     //判斷dragElement是否為null,即是否為拖拽狀态  
  29.     if(dragElement){  
  30.         var x,y;  
  31.         y = event.clientY - mouseY + objY;  
  32.         x = event.clientX - mouseX + objX;  
  33.         //改變dragElement的位置  
  34.         dragElement.style.top = y + "px";  
  35.         dragElement.style.left = x + "px";  
  36.     }  
  37. }  
  38. function docUp(){  
  39.     //停止拖拽  
  40.     dragElement = null;  
  41. }  
  42. ……  
  43. </script>  
<script type="text/javascript">
//使用該變量辨別拖拽的元素
var dragElement = null;
……
function dragInit(node){
	if(node.className == "drag"){ 
		node.onmousedown = down;
		//使用document響應mousemove事件
		document.onmousemove = move;
		node.onmouseover = over;
		//删除該函數node.onmouseup = up;
		node.style.position = "relative";
		node.style.top = "0px";
		node.style.left = "0px";
		node.dragging = false;
	}
	var children = node.childNodes;
	for(var i = 0;i < children.length; i++){
		dragInit(children[i]);
	}
}
function down(event)
{	
……
}
function move(event){
	event = event || window.event;
	//判斷dragElement是否為null,即是否為拖拽狀态
	if(dragElement){
		var x,y;
		y = event.clientY - mouseY + objY;
		x = event.clientX - mouseX + objX;
		//改變dragElement的位置
		dragElement.style.top = y + "px";
		dragElement.style.left = x + "px";
	}
}
function docUp(){
	//停止拖拽
	dragElement = null;
}
……
</script>
           

可以在修改之後的測試頁面實驗一下,無論速度多快,延遲都不會造成被拖拽元素停止移動的問題。下面就解釋一下主要的修改之處:

   1. 使用全局變量dragElement來标記目前拖拽元素。

   2. dragInit函數中,給document定義mouseover的響應函數。

   3. mousemove的響應函數的針對對象不再是this,而是dragElement。

JavaScript拖拽系列

   1. JavaScript拖拽

   2. JavaScript拖拽2——多元素、分離JS

   3. JavaScript拖拽3——解決快速拖拽的問題

   4. JavaScript拖拽4——獲得元素的位置

   5. JavaScript拖拽5——性能優化

   6. JavaScript拖拽6——修複錯誤

繼續閱讀