// 工具類,使用Util的命名空間,方便管理
var Util = new Object();
// 獲取http header里面的UserAgent,瀏覽器信息
Util.getUserAgent = navigator.userAgent;
// 是否是Gecko核心的Browser,比如Mozila、Firefox
Util.isGecko = Util.getUserAgent.indexOf( " Gecko " ) != - 1 ;
// 是否是Opera
Util.isOpera = Util.getUserAgent.indexOf( " Opera " ) != - 1 ;
// 獲取一個element的offset信息,其實就是相對于Body的padding以內的絕對坐標
// 后面一個參數如果是true則獲取offsetLeft,false則是offsetTop
// 關于offset、style、client等坐標的定義參考dindin的這個帖子:http://www.jroller.com/page/dindin/?anchor=pro_java_12
 Util.getOffset = (el, isLeft) {
var ret = 0 ;
 while (el != null ) {
ret += el[ " offset " + (isLeft ? " Left " : " Top " )];
el = el.offsetParent;
}
return ret;
};
// 將一個(參數中的funcName是這個fuction的名字)綁定到一個element上,并且以這個element的上下文運行,其實是一種繼承,這個可以google些文章看看
 Util.bind = (el, fucName) {
 return () {
return el[fucName].apply(el, arguments);
};
};
// 重新計算所有的可以拖拽的element的坐標,對同一個column下面的可拖拽圖層重新計算它們的高度而得出新的坐標,防止遮疊
// 計算出來的坐標記錄在pagePosLeft和pagePosTop兩個屬性里面
 Util.re_calcOff = (el) {
 for ( var i = 0 ; i < Util.dragArray.length; i ++ ) {
var ele = Util.dragArray[i];
ele.elm.pagePosLeft = Util.getOffset(ele.elm, true );
ele.elm.pagePosTop = Util.getOffset(ele.elm, false );
}
var nextSib = el.elm.nextSibling;
 while (nextSib) {
nextSib.pagePosTop -= el.elm.offsetHeight;
nextSib = nextSib.nextSibling;
}
};

// 隱藏Google Ig中間那個table,也就是拖拽的容器,配合show一般就是刷新用,解決一些瀏覽器的怪癖
 Util.hide = () {
Util.rootElement.style.display = " none " ;
};
// 顯示Google Ig中間那個table,解釋同上
 Util.show = () {
Util.rootElement.style.display = "" ;
};

// 移動時顯示的占位虛線框
ghostElement = null ;
// 獲取這個虛線框,通過dom動態生成
 getGhostElement = () {
 if ( ! ghostElement) {
ghostElement = createElement( " DIV " );
ghostElement.className = " modbox " ;
ghostElement.backgroundColor = "" ;
ghostElement.style.border = " 2px dashed #aaa " ;
ghostElement.innerHTML = " " ;
}
return ghostElement;
};
// 初始化可以拖拽的Element的函數,與拖拽無關的我去掉了
 draggable(el) {
// 公用的開始拖拽的函數
this ._dragStart = start_Drag;
// 公用的正在拖拽的函數
this ._drag = when_Drag;
// 公用的拖拽結束的函數
this ._dragEnd = end_Drag;
// 這個函數主要用來進行拖拽結束后的dom處理
this ._afterDrag = after_Drag;
// 是否正在被拖動,一開始當然沒有被拖動
this .isDragging = false ;
// 將這個Element的this指針注冊在elm這個變量里面,方便在自己的上下文以外調用自己的函數等,很常用的方法
this .elm = el;
// 觸發拖拽的Element,在這里就是這個div上顯示標題的那個div
this .header = getElementById(el.id + " _h " );
// 對于有i的element拖拽不同,這里檢測一下并記錄
this .hasI = this .elm.getElementsByTagName( " I " ).length > 0 ;
// 如果找到了header就綁定drag相關的event
 if ( this .header) {
// 拖拽時的叉子鼠標指針
this .header.style.cursor = " move " ;
// 將函數綁定到header和element的this上,參照那個函數的說明
Drag.init( this .header, this .elm);
// 下面三個語句將寫好的三個函數綁定給這個elemnt的三個函數鉤子上,也就實現了element從draggable繼承可拖拽的函數
this .elm.onDragStart = Util.bind( this , " _dragStart " );
this .elm.onDrag = Util.bind( this , " _drag " );
this .elm.onDragEnd = Util.bind( this , " _dragEnd " );
}
};
// 下面就是draggable里面用到的那4個
// 公用的開始拖拽的函數
 start_Drag() {
// 重置坐標,實現拖拽以后自己的位置馬上會被填充的效果
Util.re_calcOff( this );
// 記錄原先的鄰居節點,用來對比是否被移動到新的位置
this .origNextSibling = this .elm.nextSibling;
// 獲取移動的時候那個灰色的虛線框
var _ghostElement = getGhostElement();
// 獲取正在移動的這個對象的高度
var offH = this .elm.offsetHeight;
 if (Util.isGecko) {
// 修正gecko引擎的怪癖吧
offH -= parseInt(_ghostElement.style.borderTopWidth) * 2 ;
}
// 獲取正在移動的這個對象的寬度
var offW = this .elm.offsetWidth;
// 獲取left和top的坐標
var offLeft = Util.getOffset( this .elm, true );
var offTop = Util.getOffset( this .elm, false );
// 防止閃爍,現隱藏
Util.hide();
// 將自己的寬度記錄在style屬性里面
this .elm.style.width = offW + " px " ;
// 將那個灰框設定得與正在拖動的對象一樣高,比較形象
_ghostElement.style.height = offH + " px " ;
// 把灰框放到這個對象原先的位置上
this .elm.parentNode.insertBefore(_ghostElement, this .elm.nextSibling);
// 由于要拖動必須將被拖動的對象從原先的盒子模型里面抽出來,所以設定position為absolute,這個可以參考一下css布局方面的知識
this .elm.style.position = " absolute " ;
// 設置zIndex,讓它處在最前面一層,當然其實zIndex=100是讓它很靠前,如果頁面里有zIndex>100的,那……
this .elm.style.zIndex = 100 ;
// 由于position=absolute了,所以left和top實現絕對坐標定位,這就是先前計算坐標的作用,不讓這個模型亂跑,要從開始拖動的地方開始移動
this .elm.style.left = offLeft + " px " ;
this .elm.style.top = offTop + " px " ;
// 坐標設定完畢,可以顯示了,這樣就不會閃爍了
Util.show();
// 這里本來有個ig_d.G,沒搞明白干什么用的,不過沒有也可以用,誰知道麻煩告訴我一聲,不好意思
// 還沒有開始拖拽,這里做個記號
this .isDragging = false ;
return false ;
};

// 在拖拽時的相應函數,由于綁定到鼠標的move這個event上,所以會傳入鼠標的坐標clientX, clientY
 when_Drag(clientX, clientY) {
// 剛開始拖拽的時候將圖層變透明,并標記為正在被拖拽
 if ( ! this .isDragging) {
this .elm.style.filter = " alpha(opacity=70) " ;
this .elm.style.opacity = 0.7 ;
this .isDragging = true ;
}
// 被拖拽到的新的column(當然也可以是原來那個)
var found = null ;
// 最大的距離,可能是防止溢出或者什么bug
var max_distance = 100000000 ;
// 遍歷所有的可拖拽的element,尋找離當前鼠標坐標最近的那個可拖拽元素,以便后面插入
 for ( var i = 0 ; i < Util.dragArray.length; i ++ ) {
var ele = Util.dragArray[i];
// 利用勾股定理計算鼠標到遍歷到的這個元素的距離
var distance = Math.sqrt(Math.pow(clientX - ele.elm.pagePosLeft, 2 ) + Math.pow(clientY - ele.elm.pagePosTop, 2 ));
// 自己已經浮動了,所以不計算自己的
 if (ele == this ) {
continue ;
}
// 如果計算失敗繼續循環
 if (isNaN(distance)) {
continue ;
}
// 如果更小,記錄下這個距離,并將它作為found
 if (distance < max_distance) {
max_distance = distance;
found = ele;
}
}
// 準備讓灰框落腳
var _ghostElement = getGhostElement();
// 如果找到了另外的落腳點
 if (found != null && _ghostElement.nextSibling != found.elm) {
// 找到落腳點就先把灰框插進去,這就是我們看到的那個灰框停靠的特效,有點像吸附的感覺,哈哈
found.elm.parentNode.insertBefore(_ghostElement, found.elm);
 if (Util.isOpera) {
// Opera的現實問題,要隱藏/顯示后才能刷新出變化
body.style.display = " none " ;
body.style.display = "" ;
}
}
};
// 拖拽完畢
 end_Drag() {
// 拖拽完畢后執行后面的鉤子,執行after_Drag(),如果布局發生了變動了就記錄到遠程服務器,保存你拖拽后新的布局順序
 if ( this ._afterDrag()) {
// remote call to save the change
}
return true ;
};
// 拖拽后的執行鉤子
 after_Drag() {
var return = false ;
// 防止閃爍
Util.hide();
// 把拖拽時的position=absolute和相關的那些style都消除
this .elm.style.position = "" ;
this .elm.style.width = "" ;
this .elm.style.zIndex = "" ;
this .elm.style.filter = "" ;
this .elm.style.opacity = "" ;
// 獲取灰框
var ele = getGhostElement();
// 如果現在的鄰居不是原來的鄰居了
 if (ele.nextSibling != this .origNextSibling) {
// 把被拖拽的這個節點插到灰框的前面
ele.parentNode.insertBefore( this .elm, ele.nextSibling);
// 標明被拖拽了新的地方
return = true ;
}
// 移除灰框,這是這個灰框的生命周期應該就結束了
ele.parentNode.removeChild(ele);
// 修改完畢,顯示
Util.show();
 if (Util.isOpera) {
// Opera的現實問題,要隱藏/顯示后才能刷新出變化
body.style.display = " none " ;
body.style.display = "" ;
}
return return;
};

// 可拖拽Element的原形,用來將event綁定到各個鉤子,這部分市比較通用的,netvibes也是基本完全相同的實現
// 這部分推薦看dindin的這個,也會幫助理解,http://www.jroller.com/page/dindin/?anchor=pro_java_12
 var Drag = {
// 對這個element的引用,一次只能拖拽一個Element
obj: null ,
// element是被拖拽的對象的引用,elementHeader就是鼠標可以拖拽的區域
 init: (elementHeader, element) {
// 將start綁定到down事件,按下鼠標觸發start
elementHeader.down = Drag.start;
// 將element存到header的obj里面,方便header拖拽的時候引用
elementHeader.obj = element;
// 初始化絕對的坐標,因為不是position=absolute所以不會起什么作用,但是防止后面onDrag的時候parse出錯了
 if (isNaN(parseInt(element.style.left))) {
element.style.left = " 0px " ;
}
 if (isNaN(parseInt(element.style.top))) {
element.style.top = " 0px " ;
}
// 掛上空,初始化這幾個成員,在Drag.init被調用后才幫定到實際的函數,可以參照draggable里面的內容
element.onDragStart = new ();
element.onDragEnd = new ();
element.onDrag = new ();
},
// 開始拖拽的綁定,綁定到鼠標的移動的event上
 start: (event) {
var element = Drag.obj = this .obj;
// 解決不同瀏覽器的event模型不同的問題
event = Drag.fixE(event);
// 看看是不是左鍵點擊
 if (event.which != 1 ) {
// 除了左鍵都不起作用
return true ;
}
// 參照這個函數的解釋,掛上開始拖拽的鉤子
element.onDragStart();
// 記錄鼠標坐標
element.lastMouseX = event.clientX;
element.lastMouseY = event.clientY;
// 將Global的event綁定到被拖動的element上面來
up = Drag.end;
move = Drag.drag;
return false ;
},
// Element正在被拖動的函數
 drag: (event) {
// 解決不同瀏覽器的event模型不同的問題
event = Drag.fixE(event);
// 看看是不是左鍵點擊
 if (event.which == 0 ) {
// 除了左鍵都不起作用
return Drag.end();
}
// 正在被拖動的Element
var element = Drag.obj;
// 鼠標坐標
var _clientX = event.clientY;
var _clientY = event.clientX;
// 如果鼠標沒動就什么都不作
 if (element.lastMouseX == _clientY && element.lastMouseY == _clientX) {
return false ;
}
// 剛才Element的坐標
var _lastX = parseInt(element.style.top);
var _lastY = parseInt(element.style.left);
// 新的坐標
var newX, newY;
// 計算新的坐標:原先的坐標+鼠標移動的值差
newX = _lastY + _clientY - element.lastMouseX;
newY = _lastX + _clientX - element.lastMouseY;
// 修改element的顯示坐標
element.style.left = newX + " px " ;
element.style.top = newY + " px " ;
// 記錄element現在的坐標供下一次移動使用
element.lastMouseX = _clientY;
element.lastMouseY = _clientX;
// 參照這個函數的解釋,掛接上Drag時的鉤子
element.onDrag(newX, newY);
return false ;
},
// Element正在被釋放的函數,停止拖拽
 end: (event) {
// 解決不同瀏覽器的event模型不同的問題
event = Drag.fixE(event);
// 解除對Global的event的綁定
move = null ;
up = null ;
// 先記錄下onDragEnd的鉤子,好移除obj
var _onDragEndFuc = Drag.obj.onDragEnd();
// 拖拽完畢,obj清空
Drag.obj = null ;
return _onDragEndFuc;
},
// 解決不同瀏覽器的event模型不同的問題
 fixE: (ig_) {
 if ( typeof ig_ == " undefined " ) {
ig_ = event;
}
 if ( typeof ig_.layerX == " undefined " ) {
ig_.layerX = ig_.offsetX;
}
 if ( typeof ig_.layerY == " undefined " ) {
ig_.layerY = ig_.offsetY;
}
 if ( typeof ig_.which == " undefined " ) {
ig_.which = ig_.button;
}
return ig_;
}
};


// 下面是初始化的函數了,看看上面這些東西怎么被調用
 var _IG_initDrag = (el) {
// column那個容器,在google里面就是那個table布局的tbody,netvibes用的<div>
Util.rootElement = el;
// 這個tbody的行
Util._rows = Util.rootElement.tBodies[ 0 ].rows[ 0 ];
// 列,google是3列,其實也可以更多
Util.column = Util._rows.cells;
// 用來存取可拖拽的對象
Util.dragArray = new Array();
var counter = 0 ;
 for ( var i = 0 ; i < Util.column.length; i ++ ) {
// 搜索所有的column
var ele = Util.column[i];
 for ( var j = 0 ; j < ele.childNodes.length; j ++ ) {
// 搜索每一column里面的所有element
var ele1 = ele.childNodes[j];
// 如果是div就把它初始化為一個draggable對象
 if (ele1.tagName == " DIV " ) {
Util.dragArray[counter] = new draggable(ele1);
counter ++ ;
}
}
}
};

// google的頁面里可以拖動的部分的id是"t_1"
// 掛載到,載入完畢執行。不過實際上google沒有用。
// 而是寫在頁面最下面,異曲同工吧,也許直接寫在頁面是種怪癖,或者也有可能是兼容性考慮。

// 請將下面兩條被注釋掉的代碼加,到你自己下載的一個google ig頁面里面,把里面的所有其余刪除,掛上這個js也可以拖拽了,哈哈
// _table=getElementById("t_1");
// = _IG_initDrag(_table);

// 其實看懂這些代碼對學習java很有益,希望對大家能有幫助

|
|
|
| 日 | 一 | 二 | 三 | 四 | 五 | 六 |
---|
27 | 28 | 29 | 30 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|
導航
統計
- 隨筆: 32
- 文章: 427
- 評論: 144
- 引用: 0
常用鏈接
留言簿(5)
隨筆檔案
文章分類
文章檔案
java
工具
朋友
搜索
積分與排名
最新評論

閱讀排行榜
評論排行榜
|
|