对google个性主页的拖拽效果的js的完整注释[转]
对google个性主页的拖拽效果的js的完整注释[转]
发布时间:2016-12-30 来源:查字典编辑
摘要:作者:Tin出处:http://www.blogjava.net/iamtin/archive/2006/04/27/43668.html代...

作者:Tin

出处:http://www.blogjava.net/iamtin/archive/2006/04/27/43668.html

代码:http://www.blogjava.net/Files/iamtin/google_drag.rar

复制代码 代码如下:

//工具类,使用Util的命名空间,方便管理

varUtil=newObject();

//获取httpheader里面的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_javascript_12

Util.getOffset=function(el,isLeft){

varretValue=0;

while(el!=null){

retValue+=el["offset"+(isLeft?"Left":"Top")];

el=el.offsetParent;

}

returnretValue;

};

//将一个function(参数中的funcName是这个fuction的名字)绑定到一个element上,并且以这个element的上下文运行,其实是一种继承,这个可以google些文章看看

Util.bindFunction=function(el,fucName){

returnfunction(){

returnel[fucName].apply(el,arguments);

};

};

//重新计算所有的可以拖拽的element的坐标,对同一个column下面的可拖拽图层重新计算它们的高度而得出新的坐标,防止遮叠

//计算出来的坐标记录在pagePosLeft和pagePosTop两个属性里面

Util.re_calcOff=function(el){

for(vari=0;i<Util.dragArray.length;i++){

varele=Util.dragArray[i];

ele.elm.pagePosLeft=Util.getOffset(ele.elm,true);

ele.elm.pagePosTop=Util.getOffset(ele.elm,false);

}

varnextSib=el.elm.nextSibling;

while(nextSib){

nextSib.pagePosTop-=el.elm.offsetHeight;

nextSib=nextSib.nextSibling;

}

};

//隐藏GoogleIg中间那个table,也就是拖拽的容器,配合show一般就是刷新用,解决一些浏览器的怪癖

Util.hide=function(){

Util.rootElement.style.display="none";

};

//显示GoogleIg中间那个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="2pxdashed#aaa";

ghostElement.innerHTML="";

}

returnghostElement;

};

//初始化可以拖拽的Element的函数,与拖拽无关的我去掉了

functiondraggable(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

//公用的开始拖拽的函数

functionstart_Drag(){

//重置坐标,实现拖拽以后自己的位置马上会被填充的效果

Util.re_calcOff(this);

//记录原先的邻居节点,用来对比是否被移动到新的位置

this.origNextSibling=this.elm.nextSibling;

//获取移动的时候那个灰色的虚线框

var_ghostElement=getGhostElement();

//获取正在移动的这个对象的高度

varoffH=this.elm.offsetHeight;

if(Util.isGecko){

//修正gecko引擎的怪癖吧

offH-=parseInt(_ghostElement.style.borderTopWidth)*2;

}

//获取正在移动的这个对象的宽度

varoffW=this.elm.offsetWidth;

//获取left和top的坐标

varoffLeft=Util.getOffset(this.elm,true);

varoffTop=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;

returnfalse;

};

//在拖拽时的相应函数,由于绑定到鼠标的move这个event上,所以会传入鼠标的坐标clientX,clientY

functionwhen_Drag(clientX,clientY){

//刚开始拖拽的时候将图层变透明,并标记为正在被拖拽

if(!this.isDragging){

this.elm.style.filter="alpha(opacity=70)";

this.elm.style.opacity=0.7;

this.isDragging=true;

}

//被拖拽到的新的column(当然也可以是原来那个)

varfound=null;

//最大的距离,可能是防止溢出或者什么bug

varmax_distance=100000000;

//遍历所有的可拖拽的element,寻找离当前鼠标坐标最近的那个可拖拽元素,以便后面插入

for(vari=0;i<Util.dragArray.length;i++){

varele=Util.dragArray[i];

//利用勾股定理计算鼠标到遍历到的这个元素的距离

vardistance=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="";

}

}

};

//拖拽完毕

functionend_Drag(){

//拖拽完毕后执行后面的钩子,执行after_Drag(),如果布局发生了变动了就记录到远程服务器,保存你拖拽后新的布局顺序

if(this._afterDrag()){

//remotecalltosavethechange

}

returntrue;

};

//拖拽后的执行钩子

functionafter_Drag(){

varreturnValue=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="";

//获取灰框

varele=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="";

}

returnreturnValue;

};

//可拖拽Element的原形,用来将event绑定到各个钩子,这部分市比较通用的,netvibes也是基本完全相同的实现

//这部分推荐看dindin的这个,也会帮助理解,http://www.jroller.com/page/dindin/?anchor=pro_javascript_12

varDrag={

//对这个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=newFunction();

element.onDragEnd=newFunction();

element.onDrag=newFunction();

},

//开始拖拽的绑定,绑定到鼠标的移动的event上

start:function(event){

varelement=Drag.obj=this.obj;

//解决不同浏览器的event模型不同的问题

event=Drag.fixE(event);

//看看是不是左键点击

if(event.which!=1){

//除了左键都不起作用

returntrue;

}

//参照这个函数的解释,挂上开始拖拽的钩子

element.onDragStart();

//记录鼠标坐标

element.lastMouseX=event.clientX;

element.lastMouseY=event.clientY;

//将Global的event绑定到被拖动的element上面来

document.onmouseup=Drag.end;

document.onmousemove=Drag.drag;

returnfalse;

},

//Element正在被拖动的函数

drag:function(event){

//解决不同浏览器的event模型不同的问题

event=Drag.fixE(event);

//看看是不是左键点击

if(event.which==0){

//除了左键都不起作用

returnDrag.end();

}

//正在被拖动的Element

varelement=Drag.obj;

//鼠标坐标

var_clientX=event.clientY;

var_clientY=event.clientX;

//如果鼠标没动就什么都不作

if(element.lastMouseX==_clientY&&element.lastMouseY==_clientX){

returnfalse;

}

//刚才Element的坐标

var_lastX=parseInt(element.style.top);

var_lastY=parseInt(element.style.left);

//新的坐标

varnewX,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);

returnfalse;

},

//Element正在被释放的函数,停止拖拽

end:function(event){

//解决不同浏览器的event模型不同的问题

event=Drag.fixE(event);

//解除对Global的event的绑定

document.onmousemove=null;

document.onmouseup=null;

//先记录下onDragEnd的钩子,好移除obj

var_onDragEndFuc=Drag.obj.onDragEnd();

//拖拽完毕,obj清空

Drag.obj=null;

return_onDragEndFuc;

},

//解决不同浏览器的event模型不同的问题

fixE:function(ig_){

if(typeofig_=="undefined"){

ig_=window.event;

}

if(typeofig_.layerX=="undefined"){

ig_.layerX=ig_.offsetX;

}

if(typeofig_.layerY=="undefined"){

ig_.layerY=ig_.offsetY;

}

if(typeofig_.which=="undefined"){

ig_.which=ig_.button;

}

returnig_;

}

};

//下面是初始化的函数了,看看上面这些东西怎么被调用

var_IG_initDrag=function(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=newArray();

varcounter=0;

for(vari=0;i<Util.column.length;i++){

//搜索所有的column

varele=Util.column[i];

for(varj=0;j<ele.childNodes.length;j++){

//搜索每一column里面的所有element

varele1=ele.childNodes[j];

//如果是div就把它初始化为一个draggable对象

if(ele1.tagName=="DIV"){

Util.dragArray[counter]=newdraggable(ele1);

counter++;

}

}

}

};

//google的页面里可以拖动的部分的id是"t_1"

//挂载到onload,载入完毕执行。不过实际上google没有用onload。

//而是写在页面最下面,异曲同工吧,也许直接写在页面是种怪癖,或者也有可能是兼容性考虑。

//请将下面两条被注释掉的代码加,到你自己下载的一个googleig页面里面,把里面的所有其余script删除,挂上这个js也可以拖拽了,哈哈

//_table=document.getElementById("t_1");

//window.onload=_IG_initDrag(_table);

//其实看懂这些代码对学习javascript很有益,希望对大家能有帮助

推荐文章
猜你喜欢
附近的人在看
推荐阅读
拓展阅读
相关阅读
网友关注
最新Javascript教程学习
热门Javascript教程学习
编程开发子分类