原文來自:[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——修複錯誤