天天看點

JavaScript 拖放效果系列三——解決快速拖拽的問題

原文來自:[url]http://www.cainiao8.com/web/js_examples/15_tuozhuai3.html[/url]

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

元素停止移動的原因

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

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

<script type="text/javascript">
function dragInit(node){
	if(node.className == "drag"){ 
		……
		node.onmouseout = out;
		……
	}
		……
}
……
function out(){
	alert("滑鼠一出去啦,我不能再移動啦!!");
}
……
</script>
           

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

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

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

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

<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>
           

可以在修改之後的[url=http://www.cainiao8.com/web/js_examples/tuozhuai_ex3.html]測試頁面實驗一下[/url],無論速度多快,延遲都不會造成被拖拽元素停止移動的問題。下面就解釋一下主要的修改之處:

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——修複錯誤

繼續閱讀