您好,欢迎访问一九零五行业门户网

对google个性主页的拖拽效果的js的完整注释[转]_javascript技巧

作者:tin
出处:http://www.blogjava.net/iamtin/archive/2006/04/27/43668.html
代码:http://www.blogjava.net/files/iamtin/google_drag.rar
复制代码 代码如下:
// 工具类,使用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_javascript_12 
util.getoffset  =   function  (el, isleft) {
     var  retvalue  =   0 ;
     while  (el  !=   null ) {
        retvalue  +=  el[  offset    +  (isleft  ?    left   :   top  )];
        el  =  el.offsetparent;
    }
     return  retvalue;
};
// 将一个function(参数中的funcname是这个fuction的名字)绑定到一个element上,并且以这个element的上下文运行,其实是一种继承,这个可以google些文章看看 
util.bindfunction  =   function  (el, fucname) {
     return   function  () {
         return  el[fucname].apply(el, arguments);
    };
};
// 重新计算所有的可以拖拽的element的坐标,对同一个column下面的可拖拽图层重新计算它们的高度而得出新的坐标,防止遮叠 
// 计算出来的坐标记录在pageposleft和pagepostop两个属性里面 
util.re_calcoff  =   function  (el) {
     for  ( var  i  =   0 ; 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  =   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           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  =  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);
         // 看看是不是左键点击 
         if  (event.which  !=   1 ) {
             // 除了左键都不起作用 
             return   true ;
        }
         // 参照这个函数的解释,挂上开始拖拽的钩子 
        element.ondragstart();
         // 记录鼠标坐标 
        element.lastmousex  =  event.clientx;
        element.lastmousey  =  event.clienty;
         // 将global的event绑定到被拖动的element上面来 
        document.onmouseup  =  drag.end;
        document.onmousemove  =  drag.drag;
         return   false ;
    }, 
     // element正在被拖动的函数 
    drag: function  (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: 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  ( typeof  ig_  ==    undefined  ) {
            ig_  =  window.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  =   function  (el) {
     // column那个容器,在google里面就是那个table布局的tbody,netvibes用的 
    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           // 搜索所有的column 
         var  ele  =  util.column[i];
         for  ( var  j  =   0 ; 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 
// 挂载到onload,载入完毕执行。不过实际上google没有用onload。 
// 而是写在页面最下面,异曲同工吧,也许直接写在页面是种怪癖,或者也有可能是兼容性考虑。
// 请将下面两条被注释掉的代码加,到你自己下载的一个google ig页面里面,把里面的所有其余script删除,挂上这个js也可以拖拽了,哈哈 
// _table=document.getelementbyid(t_1); 
// window.onload = _ig_initdrag(_table);
// 其实看懂这些代码对学习javascript很有益,希望对大家能有帮助
其它类似信息

推荐信息