简易而又灵活的Javascript拖拽框架(三)

一、开篇

     这是这个拖拽系列的第三篇了,第一篇简单的介绍了一下这个拖拽框架,第二篇用这个框架做了一个Tab标签的拖放。这次用这个拖拽框架做一个更复杂一点的效果——跨列拖放。就像iGoogle和netvibes的个性页面布局那样。

 

二、原理

 框架在第一篇做了介绍,这里直接使用。

首先要找到每个可以拖动的item,对于每个拖动的item,对其注册组件Drag.init(handle,dragBody);并且要把这个对象所在的列赋值给这个对象

还是分三个步骤说这个拖放的过程

1、鼠标拖动开始的时候,除了要将dragGhost放到当前被拖动的对象原来的位置上,还要记录每一列的左边距,当然还是要设置被拖动对象的position

 

2、鼠标拖动的过程中

先找到拖动对象是在哪一列,通过现在拖动对象的位置和在拖动开始时记录的列的左边距相比较,得出当前拖动对象在哪一列。


 

如果在原来那一列上,则不用管了,如果在别的列上,则将dragGhost插入到这个新的列中去(用column.appendChild插入到最后)。无论是本来就在这一列的元素还是从别的列拖过来的元素,都得让拖动对象与他所在的列的每一个元素的纵坐标相比较,得出应该在这一列的什么位置,将dragGhost插入(用column.insertBefore)。至于怎么找到拖动元素应该放在这一列的什么位置,这个原理和上边找列的原理差不多,只是比较的是纵坐标的值,比较的对象是本列的所有对象(注意,遍历的时候一定要排除dragGhost和本身,要不然在本列不能向下拖动)。

3、拖动完成

ghost替换为被拖动的元素,设置相应的样式

三、代码

ContractedBlock.gif ExpandedBlockStart.gif Code
//------------------------Utility------------------------
function findPosX(obj) {//辅助函数 得到元素左边与浏览器左边的边距
    var curleft = 0;
    
if (obj && obj.offsetParent) {
        
while (obj.offsetParent) {
            curleft 
+= obj.offsetLeft;
            obj 
= obj.offsetParent;
        }
    } 
else if (obj && obj.x) curleft += obj.x;
    
return curleft;// + document.body.scrollLeft - document.body.clientLeft;
}

function findPosY(obj) {//辅助函数 得到元素上边与浏览器上边的边距
    var curtop = 0;
    
if (obj && obj.offsetParent) {
        
while (obj.offsetParent) {
            curtop 
+= obj.offsetTop;
            obj 
= obj.offsetParent;
        }
    } 
else if (obj && obj.y) curtop += obj.y;
    
return curtop;// + document.body.scrollTop - document.body.clientTop;
}


var dragGhost = document.createElement("div");
dragGhost.style.border 
= "dashed 1px #CCCCCC";
dragGhost.style.background 
= "white";
dragGhost.style.display 
= "none";
dragGhost.style.margin 
= "10px";

var container;
var columns = [];
//------------------------Start Here------------------------
window.onload = function(){
    container 
= document.getElementById("container");
    
    
for(var i=0;i<container.childNodes.length;i++){
        
if(container.childNodes[i].className == "column"){//筛选出所有的列 ff下的childNodes不可靠 :\
            columns.push(container.childNodes[i]);
        }
    }
    
for(var i=0;i<columns.length;i++){
        
var column = columns[i];
        
for(var j=0;j<column.childNodes.length;j++){
            
var item = column.childNodes[j];
            
if(item.className == "item"){
                item.column 
= column;//给每个拖拽对象要指明它属于哪一列 而且这个属性会随着拖动而更新的
                
                
new dragItem(item);
            }
        }
    }
}
var isIE = document.all;

//------------------------Drag Item------------------------
function dragItem(item){
    
//item实际上是dragBody(拖动的时候移动的整体)
    //在这里需要根据item找到handle(能够拖动的把手)
    
    
var handle;
    
for(var i=0;i<item.childNodes.length;i++){
        
if(item.childNodes[i].nodeName.toLowerCase() == "h3"){
            handle 
= item.childNodes[i];
            
break;
        }
    }
    
if(!handle)return;
    Drag.init(handle,item);
    item.onDragStart 
= function(left,top,mouseX,mouseY){
        
//开始拖动的时候设置透明度
        
        
this.style.opacity = "0.5";
        
this.style.filter = "alpha(opacity=50)";
        dragGhost.style.height 
= isIE?this.offsetHeight:this.offsetHeight - 2;
        
        
//this指的是item
        
        
this.style.width = this.offsetWidth;//因为初始的width为auto
        this.style.left = findPosX(this- 5;
        
this.style.top = findPosY(this- 5;
        
this.style.position = "absolute";
        
        
//将ghost插入到当前位置
        dragGhost.style.display = "block";
        
this.column.insertBefore(dragGhost,this);
        
        
//记录每一列的左边距 在拖动过程中判断拖动对象所在的列会用到
        this.columnsX = [];
        
for(var i=0;i<columns.length;i++){
            
this.columnsX.push(findPosX(columns[i]));
        }
            
    }
    item.onDrag 
= function(left,top,mouseX,mouseY){
    
        
//先要判断在哪一列移动
        var columnIndex = 0
        
        
for(var i=0;i<this.columnsX.length;i++){
            
if((left + this.offsetWidth/2) > this.columnsX[i]){
                columnIndex = i;
            }
        }
        
//如果columnIndex在循环中没有被赋值 则表示当前拖动对象在第一列的左边
        //此时也把它放到第一列
        
        
var column = columns[columnIndex];
        
        
if(this.column != column){
            
//之前拖动对象不在这个列
            //将ghost放置到这一列的最下方
            
            column.appendChild(dragGhost);
            
this.column = column;
        }
        
        
//然后在判断放在这一列的什么位置
        
        
var currentNode = null;
        
for(var i=0;i<this.column.childNodes.length;i++){
            
if(this.column.childNodes[i].className == "item"
            
&& this.column.childNodes[i] != this//不能跟拖动元素自己比较 否则不能在本列向下移动
            && top < findPosY(this.column.childNodes[i])){//从上到下找到第一个比拖动元素的上边距大的元素
            
                currentNode 
= this.column.childNodes[i];
                
break;
            }
        }
        
if(currentNode)
            
this.column.insertBefore(dragGhost,currentNode);
        
else//拖到最下边 没有任何一个元素的上边距比拖动元素的top大 则添加到列的最后
        
            
this.column.appendChild(dragGhost);
    }
    item.onDragEnd 
= function(left,top,mouseX,mouseY){
        
this.style.opacity = "1";
        
this.style.filter = "alpha(opacity=100)";
        
        
this.column.insertBefore(this,dragGhost);
        
        
this.style.position = "static";
        
this.style.display = "block";
        
this.style.width = "auto";
        dragGhost.style.display 
= "none";
    }
}

 如果这样不方便观看,可以下载示例。

四、示例下载

      点此下载示例

转载于:https://www.cnblogs.com/LongWay/archive/2008/09/16/1291742.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值