簡易而又靈活的Javascript拖拽框架(四)

一、開篇

似乎拖拽已經被寫爛了,沒得寫的了,可是我這次又來了~

上一次寫的是跨列拖放,這次我要帶給大家的是跨頁拖放。

可以到這里來看看效果:示例效果

說明:1、如果將方框拖動到頁簽上立刻釋放掉的話,則會被添加到該頁的第一列的第一個位置;

???? 2、如果將方框拖動到頁簽上并且停留片刻的話,則頁面就會轉換到該頁,這個時候可以在頁簽上釋放,也可以將方框拖動到此頁的具體位置釋放。

二、原理

???? 我是在跨列拖放的基礎上修改的代碼,雖然僅僅是從跨“列”升級為跨“頁“,但是這就意味著多了一個dimension。所以代碼改動比較大,尤其是初始化的代碼。

為了弄清楚代碼中的命名同時也便于闡述原理,我畫了下面的圖


?

?

1、在拖動開始時,跟之前的跨列拖拽差不多,基本上不需要修改;

2、在拖動的過程中,就需要判斷拖動module時的鼠標是否是在某個tab上,如果在tab上,則把dragGhost(拖動中占位的虛線框)隱藏了,并且設置轉換頁面的timeout(注意:這個timeout不要設置重復了,而且如果鼠標就在本頁上就不需要設置),在設置這個timeout的響應函數也要小心,必須先把拖動的module放到新的頁面然后再轉換頁面,因為鼠標雖然拖動了module,但是在html代碼中,這個module還是屬于原來的頁面(只是因為positionabsolute才讓它游離出來的),如果原來的頁面因為頁面轉換而變得不可見了,那么鼠標拖動的module也會不翼而飛的。

3、在拖動的過程中,如果鼠標不在某個tab上,首先要將timeout及時清除了,要不然在拖動時會莫名其妙的轉換頁面,剩下的跟頁面內拖放是一樣的計算方法來處理,也是先計算所在的列,然后計算再這個列的位置,在此不再累述。

4、在拖動的過程中,注意維持modulecolumn變量,這個變量對于拖放很重要,要及時而正確的更新。

5、在拖動結束的時候,如果鼠標還在某個tab上(無論這個時候頁面是不是因為鼠標的停留而改變),則把module放在這一頁的第一列的第一個位置。如果不在tab上,那么和頁面內拖放是一樣的。無論怎樣,在最后都要設置一些style以及更新個別變量,放置完畢。

三、代碼

?????? 原理說起來容易,寫起來還是很麻煩的,而且得經過很多次測試才能成功的。

?????? 不過我總結出來幾點:

?????? 1、對于任何一個對象,要分清楚這個對象是html對象還是我們自定義類的對象;

?????? 2、各種對象盡量少維持一些變量,要不然在每次動作發生的時候都會去更新一堆變量,那將是很麻煩的(或許可以將這些變量的設置封裝成對象的方法);

?????? 主要代碼如下:

ContractedBlock.gifExpandedBlockStart.gifCode
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難道是個值類型)
????????//也可以不要最后這一句?僅僅是為了數據的完整性
????????
????}
????
}

四、示例下載

????? 點此下載示例

轉載于:https://www.cnblogs.com/LongWay/archive/2008/09/23/1297173.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/379896.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/379896.shtml
英文地址,請注明出處:http://en.pswp.cn/news/379896.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java——集合的基本功能測試

* 1,boolean add<E,e> 添加* 確保此 collection 包含指定的元素&#xff08;可選操作&#xff09;。* 參數&#xff1a;e - 確定此 collection 中是否存在的元素。E - 代表Object類&#xff0c;說明該add可以添加任何對象&#xff0c;任意對象都是Object的子類對象&…

《那些年啊,那些事——一個程序員的奮斗史》——78

招人風波之后&#xff0c;就很少見武總往18樓跑了&#xff0c;大部分時間都是坐在22樓的隔間。而武總對段伏櫪的抱怨&#xff0c;也僅僅只有那次&#xff0c;后來就再也沒有提過。對于段伏櫪而言&#xff0c;還要不要招新人&#xff0c;后續如何去招新人&#xff0c;已經不是自…

python---異常處理結構

python中提供了很多不同形式的異常處理結構&#xff0c;其基本思路都是先嘗試執行代碼&#xff0c;再處理可能發生的錯誤。 try…except… 在python異常處理結構中&#xff0c;try…except…使用最為頻繁&#xff0c;其中try子句中的代碼塊為可能引發異常的語句&#xff0c;e…

用css網站布局之十步實錄 (轉載)

第一步&#xff1a;規劃網站http://www.52css.com/article.asp?id175 第二步&#xff1a;創建html模板及文件目錄等http://www.52css.com/article.asp?id176 第三步&#xff1a;將網站分為五個div 網頁基本布局http://www.52css.com/article.asp?id177 第四步&#xff1a;網…

Java——集合轉數組并對其進行遍歷

* A&#xff1a;集合的遍歷* 其實就是以此獲取集合中的每一個元素* B&#xff1a;案例* 把集合轉成數組&#xff0c;可以實現集合的遍歷* public Object[] toArray() 按適當順序&#xff08;從第一個到最后一個元素&#xff09;返回包含此列表中所有元素的數組。…

魚油賬號記錄程序(續) - 零基礎入門學習Delphi39

魚油賬號記錄程序&#xff08;續&#xff09; 讓編程改變世界 Change the world by program 課件同上一講&#xff0c;這一講主要演示編程操作和修改程序&#xff01; [buy] 獲得所有教學視頻、課件、源代碼等資源打包 [/buy] [Downlink hrefhttp://kuai.xunlei.com/d/LDKX…

python---Socket編程

Sockte是計算機之間進行網絡通信的一套程序接口&#xff0c;相當于在發送端和接收端之間建立一個通信管道。在實際應用中&#xff0c;一些遠程管理軟件和網絡安全軟件大多數依賴于Socket來實現特定功能&#xff0c;由于TCP方式在網絡編程中應用非常頻繁&#xff0c;此處將對TCP…

格式轉換-----PDF格式研究筆記(一)

格式轉換-----PDF格式研究筆記&#xff08;一&#xff09; 現在我的幾個計劃都需要我能夠對PDF格式進行解碼&#xff0c;所以找了一下資料&#xff0c;找到了一個PDF1.3的手冊&#xff0c;特放出下載&#xff0c;如果誰有更高版本的&#xff0c;請給我一份&#xff0c;謝謝。 …

(X)HTML嵌套規則

本文整理于互聯網~ 簡單認識了塊元素和內嵌元素以后&#xff0c;下面就可以羅列 XHTML 標簽的嵌套規則了&#xff1a; 1. 塊元素可以包含內聯元素或某些塊元素&#xff0c;但內聯元素卻不能包含塊元素&#xff0c;它只能包含其它的內聯元素&#xff1a;<div><h1>&…

Java——集合帶All的功能演示

package com.wsq.collection;import java.util.ArrayList; import java.util.Collection; public class Demo4_CollectionAll {public static void main(String[] args) {demo1(); //c1.addAll(c2);將c2整個集合給添加到c1中,即&#xff0c;c2集合中的每…

ASP.NET Web API 處理架構

這篇文章主要是介紹ASP.NET Web API的處理架構&#xff1a;當一個HTTP請求到達直到產生一個請求的過程。ASP.NET Web API 的處理架構圖如下&#xff0c;主要有三層組成&#xff1a;宿主&#xff08;hosting&#xff09;&#xff0c;消息處理管道&#xff08;message handler pi…

python---可執行文件的轉換

pyinstaller是常見的執行文件打包工具。該工具的安裝方式非常簡單&#xff0c;可運行在windows、MacOS X和GNU/Linux操作系統環境中&#xff0c;執行python2和python3。 用pyinstaller打包的執行文件&#xff0c;只能在于執行打包操作的系統類型相同的環境下運行。也就是說&…

Java——集合的遍歷之迭代遍歷

這些是下面的代碼中所涉及到的所有方法&#xff1a;* 迭代概述:* 集合是用來存儲元素&#xff0c;存儲的元素需要查看&#xff0c;那么就需要迭代(遍歷)* 也就是說&#xff0c;迭代就是遍歷* * public interface Iterator<E> 對 collection 進行迭代的迭代器* …

數組排序最小復雜度_進行排序的最小缺失數

數組排序最小復雜度Problem statement: 問題陳述&#xff1a; Given an array of n integers. Find the minimum number of elements from the array to remove or delete so that when the remaining elements are placed in the same sequence order form a sorted sequence…

輕松掌握Windows窗體間的數據交互(轉載)

輕松掌握Windows窗體間的數據交互作者&#xff1a;鄭佐日期&#xff1a;2004-04-05Windows 窗體是用于 Microsoft Windows 應用程序開發的、基于 .NET Framework 的新平臺。此框架提供一個有條理的、面向對象的、可擴展的類集&#xff0c;它使您得以開發豐富的 Windows 應用程序…

MATLAB安裝問題解決方案大集錦

我的安裝后的兩個問題 第一個&#xff1a;“Microsoft Visual C Runtime LibraryRuntime Error!Program:C:\Matlab7\Rin\Win32\Matlab.exeThis application has requested the runtime to terminate it in an unusual way.Please contact the applications support team for mo…

python免殺技術---shellcode的加載與執行

0x01 生成shellcode 首先通過下列命令生成一個shellcode&#xff0c;使用msfvenom -p選項來指定paylaod&#xff0c;這里選用windows/x64、exec模塊接收的參數。使用calc.exe執行彈出計算器的操作。-f選項用來執行生成的shellcdoe的編譯語言。 msfvenom -p windows/x64/exec …

成對的歌曲,其總持續時間可被60整除

Problem statement: 問題陳述&#xff1a; In a list of songs, the i-th song has duration of time[i] seconds. Return the number of pairs of songs for which their total duration in seconds is divisible by 60. Formally, we want the number of indices i < j w…

Qt中QTableWidget用法總結

QTableWidget是QT程序中常用的顯示數據表格的空間&#xff0c;很類似于VC、C#中的DataGrid。說到QTableWidget&#xff0c;就必須講一下它跟QTabelView的區別了。QTableWidget是QTableView的子類&#xff0c;主要的區別是QTableView可以使用自定義的數據模型來顯示內容(也就是先…

[轉]軟件架構師書單

"其實中國程序員&#xff0c;現在最需要的是一張安靜的書桌。"&#xff0c;的確&#xff0c;中國架構師大多缺乏系統的基礎知識&#xff0c;與其自欺欺人的宣揚"讀書無用&#xff0c;重在實踐變通&#xff0c;修身立命哲學書更重要"&#xff0c;把大好時間…