一、開篇
似乎拖拽已經被寫爛了,沒得寫的了,可是我這次又來了~
上一次寫的是跨列拖放,這次我要帶給大家的是跨頁拖放。
可以到這里來看看效果:示例效果
說明: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、各種對象盡量少維持一些變量,要不然在每次動作發生的時候都會去更新一堆變量,那將是很麻煩的(或許可以將這些變量的設置封裝成對象的方法);
?????? 主要代碼如下:


var?module?=?function(moduleElm){
????var?self?=?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(var?i=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(var?i=0;i<XDrag.tabs.length;i++){
????????????var?tabElm?=?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);
????????????function?changeTab(){
????????????????//先得把module放到當前的這一頁
????????????????//否則會隨著tab的改變而消失
????????????????
????????????????var?currentColumn?=?self.elm.currentTab.page.columns[0];
????????????????
????????????????var?flag?=?false;
????????????????for(var?i=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了
????????//先要判斷在哪一列移動
????????
????????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?=?self.column.page.columns[columnIndex];
????????
????????if(self.column?!=?column){
????????????//之前拖動對象不在這個列
????????????//將ghost放置到這一列的最下方
????????????
????????????//如果已經跨頁拖放了?也會執行這里的
????????????
????????????column.appendChild(dragGhost);
????????????self.column?=?column;
????????}
????????
????????//然后在判斷放在這一列的什么位置
????????
????????var?currentNode?=?null;
????????for(var?i=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;
????????????var?firstColumn?=?this.currentTab.page.columns[0];
????????????var?flag?=?false;
????????????for(var?i=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難道是個值類型)
????????//也可以不要最后這一句?僅僅是為了數據的完整性
????????
????}
????
}
四、示例下載
????? 點此下載示例