w一般就是刷新用,解决一些浏览器的怪癖
Util.hide
=
function
() {
Util.rootElement.style.display
=
"
none
"
;
};
//
显示Google Ig中间那个table,解释同上
Util.show
=
function
() {
Util.rootElement.style.display
=
""
;
};
//
移动时显示的占位虚线框
ghostElement
=
null
;
//
获取这个虚线框,通过dom动态生成
getGhostElement
=
function
() {
if
(
!
ghostElement) {
ghostElement
=
document.createElement(
"
DIV
"
);
ghostElement.className
=
"
modbox
"
;
ghostElement.backgroundColor
=
""
;
ghostElement.style.border
=
"
2px dashed #aaa
"
;
ghostElement.innerHTML
=
"
"
;
}
return
ghostElement;
};
//
初始化可以拖拽的Element的函数,与拖拽无关的我去掉了
function
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
=
document.getElementById(el.id
+
"
_h
"
);
//
对于有iframe的element拖拽不同,这里检测一下并记录
this
.hasIFrame
=
this
.elm.getElementsByTagName(
"
IFRAME
"
).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.bindFunction(
this
,
"
_dragStart
"
);
this
.elm.onDrag
=
Util.bindFunction(
this
,
"
_drag
"
);
this
.elm.onDragEnd
=
Util.bindFunction(
this
,
"
_dragEnd
"
);
}
};
//
下面就是draggable里面用到的那4个function
//
公用的开始拖拽的函数
function
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
function
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的现实问题,要隐藏/显示后才能刷新出变化
document.body.style.display
=
"
none
"
;
document.body.style.display
=
""
;
}
}
};
//
拖拽完毕
function
end_Drag() {
//
拖拽完毕后执行后面的钩子,执行after_Drag(),如果布局发生了变动了就记录到远程服务器,保存你拖拽后新的布局顺序
if
(
this
._afterDrag()) {
//
remote call to save the change
}
return
true
;
};
//
拖拽后的执行钩子
function
after_Drag() {
var
returnValue
=
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);
//
标明被拖拽了新的地方
returnValue
=
true
;
}
//
移除灰框,这是这个灰框的生命周期应该就结束了
ele.parentNode.removeChild(ele);
//
修改完毕,显示
Util.show();
if
(Util.isOpera) {
//
Opera的现实问题,要隐藏/显示后才能刷新出变化
document.body.style.display
=
"
none
"
;
document.body.style.display
=
""
;
}
return
returnValue;
};
//
可拖拽Element的原形,用来将event绑定到各个钩子,这部分市比较通用的,netvibes也是基本完全相同的实现
//
这部分推荐看dindin的这个,也会帮助理解,
http://www.jroller.com/page/dindin/?anchor=pro_javascript_12
var
Drag
=
{
//
对这个element的引用,一次只能拖拽一个Element
obj:
null
,
//
element是被拖拽的对象的引用,elementHeader就是鼠标可以拖拽的区域
init:
function
(elementHeader, element) {
//
将start绑定到onmousedown事件,按下鼠标触发start
elementHeader.onmousedown
=
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
"
;
}
//
挂上空Function,初始化这几个成员,在Drag.init被调用后才帮定到实际的函数,可以参照draggable里面的内容
element.onDragStart
=
new
Function();
element.onDragEnd
=
new
Function();
element.onDrag
=
new
Function();
},
//
开始拖拽的绑定,绑定到鼠标的移动的event上
start:
function
(event) {
var
element
=
Drag.obj
=
this
.obj;
//
解决不同浏览器的event模型不同的问题
event
=
Drag.fixE(event);
//
看看