// 工具類(lèi),使用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 ;
// 獲取一個(gè)element的offset信息,其實(shí)就是相對(duì)于Body的padding以內(nèi)的絕對(duì)坐標(biāo)
// 后面一個(gè)參數(shù)如果是true則獲取offsetLeft,false則是offsetTop
// 關(guān)于offset、style、client等坐標(biāo)的定義參考dindin的這個(gè)帖子: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;
};
// 將一個(gè)(參數(shù)中的funcName是這個(gè)fuction的名字)綁定到一個(gè)element上,并且以這個(gè)element的上下文運(yùn)行,其實(shí)是一種繼承,這個(gè)可以google些文章看看
 Util.bind = (el, fucName) {
 return () {
return el[fucName].apply(el, arguments);
};
};
// 重新計(jì)算所有的可以拖拽的element的坐標(biāo),對(duì)同一個(gè)column下面的可拖拽圖層重新計(jì)算它們的高度而得出新的坐標(biāo),防止遮疊
// 計(jì)算出來(lái)的坐標(biāo)記錄在pagePosLeft和pagePosTop兩個(gè)屬性里面
 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中間那個(gè)table,也就是拖拽的容器,配合show一般就是刷新用,解決一些瀏覽器的怪癖
 Util.hide = () {
Util.rootElement.style.display = " none " ;
};
// 顯示Google Ig中間那個(gè)table,解釋同上
 Util.show = () {
Util.rootElement.style.display = "" ;
};

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

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

// 可拖拽Element的原形,用來(lái)將event綁定到各個(gè)鉤子,這部分市比較通用的,netvibes也是基本完全相同的實(shí)現(xiàn)
// 這部分推薦看dindin的這個(gè),也會(huì)幫助理解,http://www.jroller.com/page/dindin/?anchor=pro_java_12
 var Drag = {
// 對(duì)這個(gè)element的引用,一次只能拖拽一個(gè)Element
obj: null ,
// element是被拖拽的對(duì)象的引用,elementHeader就是鼠標(biāo)可以拖拽的區(qū)域
 init: (elementHeader, element) {
// 將start綁定到down事件,按下鼠標(biāo)觸發(fā)start
elementHeader.down = Drag.start;
// 將element存到header的obj里面,方便header拖拽的時(shí)候引用
elementHeader.obj = element;
// 初始化絕對(duì)的坐標(biāo),因?yàn)椴皇莗osition=absolute所以不會(huì)起什么作用,但是防止后面onDrag的時(shí)候parse出錯(cuò)了
 if (isNaN(parseInt(element.style.left))) {
element.style.left = " 0px " ;
}
 if (isNaN(parseInt(element.style.top))) {
element.style.top = " 0px " ;
}
// 掛上空,初始化這幾個(gè)成員,在Drag.init被調(diào)用后才幫定到實(shí)際的函數(shù),可以參照draggable里面的內(nèi)容
element.onDragStart = new ();
element.onDragEnd = new ();
element.onDrag = new ();
},
// 開(kāi)始拖拽的綁定,綁定到鼠標(biāo)的移動(dòng)的event上
 start: (event) {
var element = Drag.obj = this .obj;
// 解決不同瀏覽器的event模型不同的問(wèn)題
event = Drag.fixE(event);
// 看看是不是左鍵點(diǎn)擊
 if (event.which != 1 ) {
// 除了左鍵都不起作用
return true ;
}
// 參照這個(gè)函數(shù)的解釋?zhuān)瑨焐祥_(kāi)始拖拽的鉤子
element.onDragStart();
// 記錄鼠標(biāo)坐標(biāo)
element.lastMouseX = event.clientX;
element.lastMouseY = event.clientY;
// 將Global的event綁定到被拖動(dòng)的element上面來(lái)
up = Drag.end;
move = Drag.drag;
return false ;
},
// Element正在被拖動(dòng)的函數(shù)
 drag: (event) {
// 解決不同瀏覽器的event模型不同的問(wèn)題
event = Drag.fixE(event);
// 看看是不是左鍵點(diǎn)擊
 if (event.which == 0 ) {
// 除了左鍵都不起作用
return Drag.end();
}
// 正在被拖動(dòng)的Element
var element = Drag.obj;
// 鼠標(biāo)坐標(biāo)
var _clientX = event.clientY;
var _clientY = event.clientX;
// 如果鼠標(biāo)沒(méi)動(dòng)就什么都不作
 if (element.lastMouseX == _clientY && element.lastMouseY == _clientX) {
return false ;
}
// 剛才Element的坐標(biāo)
var _lastX = parseInt(element.style.top);
var _lastY = parseInt(element.style.left);
// 新的坐標(biāo)
var newX, newY;
// 計(jì)算新的坐標(biāo):原先的坐標(biāo)+鼠標(biāo)移動(dòng)的值差
newX = _lastY + _clientY - element.lastMouseX;
newY = _lastX + _clientX - element.lastMouseY;
// 修改element的顯示坐標(biāo)
element.style.left = newX + " px " ;
element.style.top = newY + " px " ;
// 記錄element現(xiàn)在的坐標(biāo)供下一次移動(dòng)使用
element.lastMouseX = _clientY;
element.lastMouseY = _clientX;
// 參照這個(gè)函數(shù)的解釋?zhuān)瑨旖由螪rag時(shí)的鉤子
element.onDrag(newX, newY);
return false ;
},
// Element正在被釋放的函數(shù),停止拖拽
 end: (event) {
// 解決不同瀏覽器的event模型不同的問(wèn)題
event = Drag.fixE(event);
// 解除對(duì)Global的event的綁定
move = null ;
up = null ;
// 先記錄下onDragEnd的鉤子,好移除obj
var _onDragEndFuc = Drag.obj.onDragEnd();
// 拖拽完畢,obj清空
Drag.obj = null ;
return _onDragEndFuc;
},
// 解決不同瀏覽器的event模型不同的問(wèn)題
 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_;
}
};


// 下面是初始化的函數(shù)了,看看上面這些東西怎么被調(diào)用
 var _IG_initDrag = (el) {
// column那個(gè)容器,在google里面就是那個(gè)table布局的tbody,netvibes用的<div>
Util.rootElement = el;
// 這個(gè)tbody的行
Util._rows = Util.rootElement.tBodies[ 0 ].rows[ 0 ];
// 列,google是3列,其實(shí)也可以更多
Util.column = Util._rows.cells;
// 用來(lái)存取可拖拽的對(duì)象
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就把它初始化為一個(gè)draggable對(duì)象
 if (ele1.tagName == " DIV " ) {
Util.dragArray[counter] = new draggable(ele1);
counter ++ ;
}
}
}
};

// google的頁(yè)面里可以拖動(dòng)的部分的id是"t_1"
// 掛載到,載入完畢執(zhí)行。不過(guò)實(shí)際上google沒(méi)有用。
// 而是寫(xiě)在頁(yè)面最下面,異曲同工吧,也許直接寫(xiě)在頁(yè)面是種怪癖,或者也有可能是兼容性考慮。

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

// 其實(shí)看懂這些代碼對(duì)學(xué)習(xí)java很有益,希望對(duì)大家能有幫助

|
|
|
| 日 | 一 | 二 | 三 | 四 | 五 | 六 |
---|
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 |
|
導(dǎo)航
統(tǒng)計(jì)
- 隨筆: 32
- 文章: 427
- 評(píng)論: 144
- 引用: 0
常用鏈接
留言簿(5)
隨筆檔案
文章分類(lèi)
文章檔案
java
工具
朋友
搜索
積分與排名
最新評(píng)論

閱讀排行榜
評(píng)論排行榜
|
|