posts - 11, comments - 7, trackbacks - 0, articles - 1
这篇将介绍网页中元素如何实现拖拽效果。
让元素在页面中移动,其实并不复杂,总体思想是分为以下几点。
1.重载页面中的mouse事件。
2.告诉页面那些元素可以移动。
3.获取鼠标和元素在页面中的坐标值。
4.改变元素的坐标值使其移动。
以上篇制作象棋棋盘为基础,来介绍程序如何实现。
在<div id="chessboard"></div>的最下面添加一个div元素。
如:
<div id="chessboard">


    
<div id="helpContainer" style="position:absolute;display:none;z-index:10"></div>
</div>

添加这个元素的作用是为了使被拖拽元素在拖拽时显示在所有棋子之上所使用的临时元素。

首先我们要重载需要移动元素的onmousedown事件。当鼠标点击item时就把当前item赋给javascript中的全局变量dragObject,即告诉了页面需要移动的是哪个item。
并且取得了当前鼠标相对于item的坐标,以在移动元素时使用。
var dragObject = null;
var mouseOffset = null;
var helpContainer = null;
var parentTarget = null;

Number.prototype.NaN0
=function(){return isNaN(this)?0:this;}

//重载需要移动的item的onmousedown事件
function makeDragDropable(item){
    
if(!item) return;
    item.onmousedown 
= function(ev){
        dragObject 
= this;
        mouseOffset 
= getMouseOffset(this, ev);
        
if(dragObject)
            helpContainer.appendChild(dragObject.cloneNode(
true));    //克隆元素到helpContainer里
       
parentTarget = dragObject.parentNode;
        return false;
    };
}
//取得鼠标相对于item的坐标
function getMouseOffset(target, ev){
    ev 
= ev || window.event;    //ev在Firefox中只能被当前函数获取,而在IE里是全局变局
    var docPos = getPosition(target);
    
var mousePos = mouseCoords(ev);
    
return {x:mousePos.x - docPos.x, y:mousePos.y - docPos.y};
}
//item相对于整个document的绝对坐标
function getPosition(e){
    
var left = 0;
    
var top = 0;
    
while(e.offsetParent){
        left 
+= e.offsetLeft + (e.currentStyle?(parseInt(e.currentStyle.borderLeftWidth)).NaN0():0);
        top 
+= e.offsetTop  + (e.currentStyle?(parseInt(e.currentStyle.borderTopWidth)).NaN0():0);
        e 
= e.offsetParent;
    }
    left 
+= e.offsetLeft + (e.currentStyle?(parseInt(e.currentStyle.borderLeftWidth)).NaN0():0);
    top 
+= e.offsetTop  + (e.currentStyle?(parseInt(e.currentStyle.borderTopWidth)).NaN0():0);
    
    
return {x:left, y:top};
}
//mouse相对于整个document的绝对坐标
function mouseCoords(ev){
    
if(ev.pageX || ev.pageY){
        
return {x:ev.pageX, y:ev.pageY};
    }
    
return {x:ev.clientX + document.body.scrollLeft - document.body.clientLeft,
            y:ev.clientY 
+ document.body.scrollTop - document.body.clientTop};
}
window.onload 
= function(){
    helpContainer 
= document.getElementById("helpContainer");
   
boardPos = getPosition(document.getElementById("chessboard"));
    makeDragDropable(document.getElementById("zhu_0_0"));    //使“车”这个棋子拥有了拖拽的基础,其它棋子的拖拽添加方法一样。
}
需要的信息都取得了,为了使item移动,必需重载页面的onmousemove事件。
document.onmousemove = mouseMove;
function mouseMove(ev){
    ev 
= ev || window.event;
    
var target = ev.target || ev.srcElement;
    
var mousePos = mouseCoords(ev);
    
//隐藏当前元素,显示help临时元素
    helpContainer.style.display = "";
    dragObject.style.display  
= "none";
    
//移动help元素
    helpContainer.style.top  = mousePos.y - mouseOffset.y - boardPos.y;
    helpContainer.style.left 
= mousePos.x - mouseOffset.x - boardPos.x;
}
到这里移动元素的功能就实现了,但在下象棋时棋子只能在格子的十字中心的位置上。
下面我就介绍如何给棋子添加定位功能。
重载onmouseup事件,即在鼠标提起时所触发的事件。
document.onmouseup = mouseUp;
function mouseUp(ev){
    ev 
= ev || window.event;
    
var mousePos = mouseCoords(ev);
    
var dLength = dropTargets.length;
    
//判断当前棋子是否在可走集合内
    for(var i = 0; i < dLength; i++){
        curTarget 
= dropTargets[i];
        curTargetPos 
= getPosition(curTarget);
        curTargetWidth 
= parseInt(curTarget.offsetWidth);
        curTargetHeight 
= parseInt(curTarget.offsetHeight);
        
        
if(mousePos.x > curTargetPos.x
            
&& mousePos.x < (curTargetPos.x + curTargetWidth)
            
&& mousePos.y > curTargetPos.y
            
&& mousePos.y < (curTargetPos.y + curTargetHeight)){
            resetChessmanPos();
            
if(eatChessman(curTarget)){
                
//目标元素添加被拖拽棋子
                curTarget.appendChild(dragObject);
            }
            curTarget 
= null;
        }
else{
            resetChessmanPos();
        }
    }
    dragObject 
= null;
}
//是否可以吃棋子
function eatChessman(curTarget){
    
var obj = curTarget.firstChild;
    
if(!obj) return true;
    
if(dragObject){
        
var temp = obj.id.split("_");
        
var temp2 = dragObject.id.split("_");
        
if(temp[1== temp2[1]){
            dragObject.style.top 
= 0;
            dragObject.style.left 
= 0;
            
return false;
        }
else{
            //eatContainer.appendChild(obj);
            
return true;
        }
    }
    
return false;
}
//重设棋子坐标
function resetChessmanPos(){
    dragObject.style.top 
= 0;
    dragObject.style.left 
= 0;
    dragObject.style.display 
= "";
    helpContainer.style.display 
= "none";
}
var dropTargets = [];
function addDragDropTarget(dropTarget){
    dropTargets.push(dropTarget);
}
window.onload 
= function(){
    
//在已有的代码中添加如下代码
    for(var row = 0; row < 10; row++){
        
for(var col = 0; col < 9; col++){
            
//添加棋子可走范围集合
            addDragDropTarget(document.getElementById("grid_"+row+"_"+col));
        }
    }
}
棋子拖拽的功能基本上完成了。
不过象棋是有规则的哦,下面把规则加进去。
function chessRule(curTarget){
    
var pTemp = parentTarget.id.split("_");
    
var dTemp = dragObject.id.split("_")[0];
    
var uTemp = dragObject.id.split("_")[1];
    
var cTemp = curTarget.id.split("_");
    
var y1 = cTemp[1];
    
var x1 = cTemp[2];
    
var y2 = pTemp[1];
    
var x2 = pTemp[2];
    
    
switch(dTemp){
        
case "zhu":
            
if(x1 == x2 || y1 == y2){
                
if(x1 == x2){
                    
return !isBlock(x1, y1, y2, "y");
                }
                
if(y1 == y2){
                    
return !isBlock(y1, x1, x2, "x");
                }
            }
else{
                
return false;
            }
            
break;
        
case "ma":
            
var n = new Array(1221-1-2-2-1);
            
var m = new Array(-2-11221-1-2);
            
for(var i = 0; i < 8; i++){
                
if((n[i]+parseInt(y2)) == y1 && (m[i]+parseInt(x2)) == x1){
                    
if(Math.abs(n[i]) > Math.abs(m[i])){
                        
var obj = document.getElementById("grid_"+(parseInt(y2)+n[i]/2)+"_"+x2);
                        
if(obj.firstChild)
                            
return false;
                        
else
                            
return true;
                    }
else{
                        
var obj = document.getElementById("grid_"+y2+"_"+(parseInt(x2)+m[i]/2));
                        
if(obj.firstChild)
                            
return false;
                        
else
                            
return true;
                    }
                }
            }
            
return false;
            
break;
        
case "xiang":
            
if(uTemp == 0 && y1 > 4){
                
return false;
            }
else if(uTemp == 1 && y1 < 5){
                
return false;
            }
else{
                
var n = new Array(22-2-2);
                
var m = new Array(-222-2);
                
return loopPos(x1, y1, x2, y2, n, m);
            }
            
break;
        
case "shi":
            
var n = new Array(-11-11);
            
var m = new Array(-1-111);
            
if(x1 < 3 || x1 > 5){
                
return false;
            }
else if(uTemp == 0 && y1 > 2){
                
return false;
            }
else if(uTemp == 1 && y1 < 7){
                
return false;
            }
else{
                
return loopPos(x1, y1, x2, y2, n, m);
            }
            
break;
        
case "jiang":
        
case "shuai":
            
var n = new Array(010-1);
            
var m = new Array(-1010);
            
if(x1 < 3 || x1 > 5){
                
return false;
            }
else if(uTemp == 0 && y1 > 2){
                
return false;
            }
else if(uTemp == 1 && y1 < 7){
                
return false;
            }
else{
                
return loopPos(x1, y1, x2, y2, n, m);
            }
            
break;
        
case "pao":
            
if(x2 == x1 || y2 == y1){
                
if(x2 == x1){
                    
if(isBlock(x1, y1, y2, "y"&& isEat(curTarget, uTemp)){
                        
return true;
                    }
else if(!isBlock(x1, y1, y2, "y"&& isEat(curTarget, uTemp)){
                        
return false;
                    }
else if(isBlock(x1, y1, y2, "y"&& !isEat(curTarget, uTemp)){
                        
return false;
                    }
                    
return true;
                }
else if(y2 == y1){
                    
if(isBlock(y1, x1, x2, "x"&& isEat(curTarget, uTemp)){
                        
return true;
                    }
else if(!isBlock(y1, x1, x2, "x"&& isEat(curTarget, uTemp)){
                        
return false;
                    }
else if(isBlock(y1, x1, x2, "x"&& !isEat(curTarget, uTemp)){
                        
return false;
                    }
                    
return true;
                }
            }
else{
                
return false;
            }
            
break;
        
case "bing":
        
case "zu":
            
if(uTemp == 0){
                
if(y2 > 4){
                    
var n = new Array(10-1);
                    
var m = new Array(010);
                    
return loopPos(x1, y1, x2, y2, n, m);
                }
else{
                    
if(parseInt(x2) == x1 && (parseInt(y2)+1== y1){
                        
return true;
                    }
else{
                        
return false;
                    }
                }
            }
else if(uTemp == 1){
                
if(y2 < 5){
                    
var n = new Array(-101);
                    
var m = new Array(0-10);
                    
return loopPos(x1, y1, x2, y2, n, m);
                }
else{
                    
if(parseInt(x2) == x1 && (parseInt(y2)-1== y1){
                        
return true;
                    }
else{
                        
return false;
                    }
                }
            }
            
break;
    }
    
return true;
}

function loopPos(x1, y1, x2, y2, n, m){
    
var l = n.length;
    
for(var i = 0; i < l; i++){
        
if((parseInt(x2)+n[i]) == x1 && (parseInt(y2)+m[i]) == y1){
            
return true;
        }
    }
    
return false;
}

function isEat(curTarget, uTemp){
    
if(curTarget.firstChild && curTarget.firstChild.id.split("_")[1!= uTemp){
        
return true
    }
else{
        
return false;
    }
}

function isBlock(num1, num2, num3, flag){
    
var t1 = Math.max(num2, num3);
    
var t2 = Math.min(num2, num3);
    
var temp = null;
    
for(var i = t2+1; i < t1; i++){
        
if(flag == "x"){
            temp 
= document.getElementById("grid_"+num1+"_"+i);
        }
else{
            temp 
= document.getElementById("grid_"+i+"_"+num1);
        }
        
if(temp.firstChild != null)
            
return true;
    }
    
return false;
}

对function mouseUp(ev)方法添加规则部分。
function mouseUp(ev){
    ev 
= ev || window.event;
    
var mousePos = mouseCoords(ev);
    
var dLength = dropTargets.length;
    
//判断当前棋子是否在可走集合内
    for(var i = 0; i < dLength; i++){
        curTarget 
= dropTargets[i];
        curTargetPos 
= getPosition(curTarget);
        curTargetWidth 
= parseInt(curTarget.offsetWidth);
        curTargetHeight 
= parseInt(curTarget.offsetHeight);
        
        
if(mousePos.x > curTargetPos.x
            
&& mousePos.x < (curTargetPos.x + curTargetWidth)
            
&& mousePos.y > curTargetPos.y
            
&& mousePos.y < (curTargetPos.y + curTargetHeight)){
            
if(chessRule(curTarget)){
                resetChessmanPos();
                
if(eatChessman(curTarget)){
                    
//目标元素添加被拖拽棋子
                    curTarget.appendChild(dragObject);
                }
                curTarget 
= null;
            }
else{
                resetChessmanPos();
            }
        }
else{
            resetChessmanPos();
        }
    }
    dragObject 
= null;
}
前台部分基本完成了。下一贴将介绍如何利用DWR与后台进行交互。

Feedback

# re: 网络象棋之二(拖拽的实现)  回复  更多评论   

2007-09-30 10:52 by BeanSoft
写的太好了 支持一下!

# re: 网络象棋之二(拖拽的实现)  回复  更多评论   

2007-09-30 10:58 by Reg
boardPos 未定义

# re: 网络象棋之二(拖拽的实现)  回复  更多评论   

2007-09-30 12:58 by 狂奔的蜗牛
十分感谢Reg,复制代码的时候有遗漏,错误我已经修正。
在window.onload中加入
boardPos = getPosition(document.getElementById("chessboard"));

# re: 网络象棋之二(拖拽的实现)  回复  更多评论   

2007-09-30 13:54 by 千里冰封
在网页上可以拖动,的确是很爽的事情

只有注册用户登录后才能发表评论。


网站导航: