简易而又灵活的Javascript拖拽框架(四)
2009-11-07 19:16
399 查看
本文示例源代码或素材下载
一、开篇
似乎拖拽已经被写烂了,没得写的了,可是我这次又来了~
上一次写的是跨列拖放,这次我要带给大家的是跨页拖放。
可以到这里来看看效果:示例效果
说明:1、如果将方框拖动到页签上立刻释放掉的话,则会被添加到该页的第一列的第一个位置;
2、如果将方框拖动到页签上并且停留片刻的话,则页面就会转换到该页,这个时候可以在页签上释放,也可以将方框拖动到此页的具体位置释放。
二、原理
我是在跨列拖放的基础上修改的代码,虽然仅仅是从跨“列”升级为跨“页“,但是这就意味着多了一个dimension。所以代码改动比较大,尤其是初始化的代码。
为了弄清楚代码中的命名同时也便于阐述原理,我画了下面的图
1、在拖动开始时,跟之前的跨列拖拽差不多,基本上不需要修改;
2、在拖动的过程中,就需要判断拖动module时的鼠标是否是在某个tab上,如果在tab上,则把dragGhost(拖动中占位的虚线框)隐藏了,并且设置转换页面的timeout(注意:这个timeout不要设置重复了,而且如果鼠标就在本页上就不需要设置),在设置这个timeout的响应函数也要小心,必须先把拖动的module放到新的页面然后再转换页面,因为鼠标虽然拖动了module,但是在html代码中,这个module还是属于原来的页面(只是因为position为absolute才让它游离出来的),如果原来的页面因为页面转换而变得不可见了,那么鼠标拖动的module也会不翼而飞的。
3、在拖动的过程中,如果鼠标不在某个tab上,首先要将timeout及时清除了,要不然在拖动时会莫名其妙的转换页面,剩下的跟页面内拖放是一样的计算方法来处理,也是先计算所在的列,然后计算再这个列的位置,在此不再累述。
5、在拖动结束的时候,如果鼠标还在某个tab上(无论这个时候页面是不是因为鼠标的停留而改变),则把module放在这一页的第一列的第一个位置。如果不在tab上,那么和页面内拖放是一样的。无论怎样,在最后都要设置一些style以及更新个别变量,放置完毕。
三、代码
原理说起来容易,写起来还是很麻烦的,而且得经过很多次测试才能成功的。
不过我总结出来几点:
1、对于任何一个对象,要分清楚这个对象是html对象还是我们自定义类的对象;
2、各种对象尽量少维持一些变量,要不然在每次动作发生的时候都会去更新一堆变量,那将是很麻烦的(或许可以将这些变量的设置封装成对象的方法);
主要代码如下:
Code
一、开篇
似乎拖拽已经被写烂了,没得写的了,可是我这次又来了~
上一次写的是跨列拖放,这次我要带给大家的是跨页拖放。
可以到这里来看看效果:示例效果
说明:1、如果将方框拖动到页签上立刻释放掉的话,则会被添加到该页的第一列的第一个位置;
2、如果将方框拖动到页签上并且停留片刻的话,则页面就会转换到该页,这个时候可以在页签上释放,也可以将方框拖动到此页的具体位置释放。
二、原理
我是在跨列拖放的基础上修改的代码,虽然仅仅是从跨“列”升级为跨“页“,但是这就意味着多了一个dimension。所以代码改动比较大,尤其是初始化的代码。
为了弄清楚代码中的命名同时也便于阐述原理,我画了下面的图
1、在拖动开始时,跟之前的跨列拖拽差不多,基本上不需要修改;
2、在拖动的过程中,就需要判断拖动module时的鼠标是否是在某个tab上,如果在tab上,则把dragGhost(拖动中占位的虚线框)隐藏了,并且设置转换页面的timeout(注意:这个timeout不要设置重复了,而且如果鼠标就在本页上就不需要设置),在设置这个timeout的响应函数也要小心,必须先把拖动的module放到新的页面然后再转换页面,因为鼠标虽然拖动了module,但是在html代码中,这个module还是属于原来的页面(只是因为position为absolute才让它游离出来的),如果原来的页面因为页面转换而变得不可见了,那么鼠标拖动的module也会不翼而飞的。
3、在拖动的过程中,如果鼠标不在某个tab上,首先要将timeout及时清除了,要不然在拖动时会莫名其妙的转换页面,剩下的跟页面内拖放是一样的计算方法来处理,也是先计算所在的列,然后计算再这个列的位置,在此不再累述。
上一次写的是跨列拖放,这次我要带给大家的是跨页拖放。
4、在拖动的过程中,注意维持module的column变量,这个变量对于拖放很重要,要及时而正确的更新。5、在拖动结束的时候,如果鼠标还在某个tab上(无论这个时候页面是不是因为鼠标的停留而改变),则把module放在这一页的第一列的第一个位置。如果不在tab上,那么和页面内拖放是一样的。无论怎样,在最后都要设置一些style以及更新个别变量,放置完毕。
三、代码
原理说起来容易,写起来还是很麻烦的,而且得经过很多次测试才能成功的。
不过我总结出来几点:
1、对于任何一个对象,要分清楚这个对象是html对象还是我们自定义类的对象;
2、各种对象尽量少维持一些变量,要不然在每次动作发生的时候都会去更新一堆变量,那将是很麻烦的(或许可以将这些变量的设置封装成对象的方法);
主要代码如下:
Code
varmodule=function(moduleElm){ varself=this; this.elm=moduleElm; this.elm.module=this; this.column=moduleElm.column; this.page=this.column.page; this.handle=this.elm.getElementsByTagName("h3")[0]; //这里只是为了各个页面的module看起来不一样所以另外设置一下style //page的id也是为了这个目的而加的其他地方page的id是用不上的 switch(this.page.id){ case"page1":this.handle.style.backgroundColor="red";break; case"page2":this.handle.style.backgroundColor="blue";break; case"page3":this.handle.style.backgroundColor="black";break; case"page4":this.handle.style.backgroundColor="#CCCCCC";break; } if(this.handle&&this.elm){ Drag.init(this.handle,this.elm); }else{ return; } this.elm.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"; self.column.insertBefore(dragGhost,this); //记录每一列的左边距在拖动过程中判断拖动对象所在的列会用到 this.columnsX=[]; for(vari=0;i<self.column.page.columns.length;i++){ this.columnsX.push(findPosX(self.column.page.columns[i])); } } this.elm.onDrag=function(left,top,mouseX,mouseY){ this.currentTab=null; //判断是否在tab上 for(vari=0;i<XDrag.tabs.length;i++){ vartabElm=XDrag.tabs[i].elm; if((findPosX(tabElm)<mouseX)&& (findPosX(tabElm)+tabElm.offsetWidth>mouseX)&& (findPosY(tabElm)<mouseY)&& (findPosY(tabElm)+tabElm.offsetHeight>mouseY)){ this.currentTab=XDrag.tabs[i]; break; } } if(this.currentTab!=null){ if(dragGhost.parentNode) dragGhost.parentNode.removeChild(dragGhost); functionchangeTab(){ //先得把module放到当前的这一页 //否则会随着tab的改变而消失 varcurrentColumn=self.elm.currentTab.page.columns[0]; varflag=false; for(vari=0;i<currentColumn.childNodes.length;i++){ if(currentColumn.childNodes[i].nodeName.toLowerCase()=="div"){ currentColumn.insertBefore(self.elm,currentColumn.childNodes[i]); flag=true; break; } } if(!flag) currentColumn.appendChild(this); self.column=currentColumn;//将拖动的module添加到这一页的第一列因为display还为absolute所以module还跟着鼠标在走 self.elm.currentTab.select(); XDrag.changeTabTimeoutId==null; } //如果Timeout不为空(防止重复设置Timeout)而且移动到的tab不是当前的tab(如果是当前tab则不需要改变tab页了) if(XDrag.changeTabTimeoutId==null&&this.currentTab!=XDrag.selectedTab) XDrag.changeTabTimeoutId=setTimeout(changeTab,XDrag.changeTabTimeout); return;//如果鼠标在tab上则不必理会页面内的移动了 } //以下是计算在页面内拖拽的代码 clearTimeout(XDrag.changeTabTimeoutId); XDrag.changeTabTimeoutId=null;//既然鼠标都没有在tab上了当然就应该清空timeout了 //先要判断在哪一列移动 varcolumnIndex=0; for(vari=0;i<this.columnsX.length;i++){ if((left+this.offsetWidth/2)>this.columnsX[i]){ columnIndex=i; } } //如果columnIndex在循环中没有被赋值则表示当前拖动对象在第一列的左边 //此时也把它放到第一列 varcolumn=self.column.page.columns[columnIndex]; if(self.column!=column){ //之前拖动对象不在这个列 //将ghost放置到这一列的最下方 //如果已经跨页拖放了也会执行这里的 column.appendChild(dragGhost); self.column=column; } //然后在判断放在这一列的什么位置 varcurrentNode=null; for(vari=0;i<self.column.childNodes.length;i++){ if(self.column.childNodes[i].className=="item" &&self.column.childNodes[i]!=this//不能跟拖动元素自己比较否则不能在本列向下移动 &&top<findPosY(self.column.childNodes[i])){//从上到下找到第一个比拖动元素的上边距大的元素 currentNode=self.column.childNodes[i]; break; } } if(currentNode) self.column.insertBefore(dragGhost,currentNode); else//拖到最下边没有任何一个元素的上边距比拖动元素的top大则添加到列的最后 self.column.appendChild(dragGhost); } this.elm.onDragEnd=function(left,top,mouseX,mouseY){ if(this.currentTab!=null){ //this.currentTab!=null表示鼠标拖拽的module在tab上释放无论这个时候tab是否因为鼠标的停留而转换了页签 clearTimeout(XDrag.changeTabTimeoutId); XDrag.changeTabTimeoutId=null; varfirstColumn=this.currentTab.page.columns[0]; varflag=false; for(vari=0;i<firstColumn.childNodes.length;i++){ if(firstColumn.childNodes[i].nodeName.toLowerCase()=="div"){ firstColumn.insertBefore(this,firstColumn.childNodes[i]); flag=true; break; } } if(!flag) firstColumn.appendChild(this); self.column=firstColumn; }else{ self.column.insertBefore(this,dragGhost); } this.style.opacity="1"; this.style.filter="alpha(opacity=100)"; this.style.position="static"; this.style.display="block"; this.style.width="auto"; dragGhost.style.display="none"; self.page=self.column.page;//需要手动更新(奇怪self.page难道是个值类型) //也可以不要最后这一句仅仅是为了数据的完整性 } }
相关文章推荐
- 简易而又灵活的Javascript拖拽框架(一)
- 简易而又灵活的Javascript拖拽框架(一)
- 简易而又灵活的Javascript拖拽框架(三)
- 简易而又灵活的Javascript拖拽框架(三)
- 简易而又灵活的Javascript拖拽框架(五)
- 简易而又灵活的Javascript拖拽框架(一)
- 简易而又灵活的Javascript拖拽框架(二)
- 简易而又灵活的Javascript拖拽框架(五)
- 简易而又灵活的Javascript拖拽框架(四)
- 简易而又灵活的Javascript拖拽框架(一)
- 简易而又灵活的Javascript拖拽框架(五)
- 简易而又灵活的Javascript拖拽框架(二)
- 简易而又灵活的Javascript拖拽框架(三)
- 简易而又灵活的Javascript拖拽框架(二)
- 简易javascript框架
- 随手记:为系统设计一套简易的JavaScript框架需要考虑的要素
- javaScript简易运动框架封装——和派孔明
- Bootstrap 基于HTML,CSS,JAVASCRIPT的简洁灵活的流行前端框架及交互组件集
- javascript 框架的基础与简易框架
- 百度Popup.js弹出框进化版 拖拽小框架发布 兼容IE6/7/8,Firefox,Chrome-javascript技巧