(十) 模拟 HTML5 实现 DragDrop

DragDrop 看似简单,实现起来却不大容易。 HTML5 已经提供了用于支持 DragDrop 的事件。使用这些事件可以方便实现 dragdrop。介于有些朋友对 HTML5 的 dragdrop 不熟,在这里先介绍下标准的 dragdrop 。

dragdrop 不是新物,早在 IE4 就有了。但那时只是 IE 的独家技能,所以标准浏览器不支持此事件,现在 HTML5 采用了 IE 的方法,故目前最新版浏览器都支持 DragDrop 。

DragDrop 是 Drag (拖动) Drop(放下) 两个操作。

为实现 Drag ,需要知道以下的事件:

  • dragstart - 拖动开始事件
  • drag - 拖动时,这个事件不断出现
  • dragend - 拖动结束事件

 

为实现 Drop,需要知道以下的事件:

  • dragenter - 拖到当前区事件
  • dragover - 拖到当前区时,不断出现
  • dragleave - 拖出事件
  • drop - 在当前区停下事件

 

假如拖动一个元素到另一个元素, 发生事件的顺序为:

 

dragstart - drag (不断) - [ dragenter - dragover/drag (交替) - dragleave/drop - ] dragend

拖动事件的参数 e, 有个成员 dataTransfer , 表示当前拖动的数据。

 

默认下, img 和 a 标签可拖到。如果需要其它节点也支持拖动,必须指明  draggable="true" 。

 

 

根据上文,你肯能会写这样的代码:

 

 

 

  <div id="et">拖动委托层</div>

  <div id="drag" draggable="true">

     被拖动

  </div>

  <div class="asd" id="zone">

     拖动区域
</div> <script> $('drag').on('dragstart', function(e){ console.log(e.type); }).on('drag', function(e){ console.log(e.type); }).on('dragend', function(e){ console.log(e.type); }); </script>

但这个代码只能在 Chrome 正常执行。

对于 IE, 则需要先选择字,然后拖。

对于 Safari, 需加如下代码:

 

    <style>

           [draggable = true] {

                -khtml-user-drag: element;

            }

    </style>

对于 Firefox, 除了加上面的代码,还需加

 

function dragstart(e){

   e.dataTransfer.setData('Text', this.id);  // 火狐必须加这句

}

目前,各浏览器对 DragDrop 的支持不同。老浏览器也不支持 DragDrop 。

 

所以,必须找一个和谐的办法。

 

我的目标是模拟浏览器的 dragdrop, 让它和浏览器原生的一样。

先调用一个函数:

$('d1').setDraggable(true); // 设置可拖动

然后这个对象便能拖动,如果还要设置事件,可以:

$('drag').on('dragstart', function(e){

          console.log(e.type);

     }).on('drag',  function(e){

          console.log(e.type);

     }).on('dragend',  function(e){

          console.log(e.type);

    });

对于目标元素,同样可设置事件,处理拖到当前元素时的处理

$('zone1').on('dragenter', function(e){                 trace("dragenter");                 return false;             }).on('dragover', function(e){                 trace("dragover");                 return false;             }).on('dragleave', function(e){                 trace("dragleave");                 return false;             }).on('drop', function(e){                 trace("drop");             });

下面介绍如何实现:

对于 Drag ,需要用 mouse 事件模拟。

先写3个函数:分别处理 mousedown,  mousemove,  mouseup , 这个相对简单,不多废话。

 

 

function mousedown(e ){

   

     // 左键才继续

     if(e.which != 1)

         return;



     // 初始化位置。



     // 暂时保存导致事件发生的目标。

     Drag.target = this;



     // 手动触发  dragstart

    this.trigger('dragstart', e);

    

    document.on('mouseup', mouseup).on('mousemove', mousemove);

}



function mouseup(e ){

   

   // 左键才继续

  if(e.which != 1)

      return;



    // 手动触发  dragend

    this.trigger('dragend', e);



   // 通知已发生 Drop 事件。

    Drag.onDrop(e);



    document.un('mousemove', mousemove).un('mouseup', mouseup);

}





function mousemove(e )



    // 手动触发  drag

    this.trigger('drag', e);



     // 移动目标。

}





然后是实现 Drop,一个 element 拖动时如何正确判断当前到上面元素,并触发那个元素的 drop 事件?

方案甲:

  判断目标区域 Zone 是否发生 mouseenter 事件, 在 mouseenter 事件处理是否在拖动,如果同时发生 mouseenter 和 drag ,则 发生 dragenter 。

 

方案乙:

  在拖动时不断计算目标位置的坐标 (Bound) 和 当前元素,如果进入则发生 dragenter 。

  因此,先写一个函数判断是否在目标内:

 

function isEnter(bound, box){

     return ((bound.right < box.right && bound.right > box.left) || (bound.left < box.right && bound.left > box.left)) &&

					  ((bound.bottom < box.bottom && bound.bottom > box.top) || (bound.top < box.bottom && bound.top > box.top)) ;

}





然后在 drag 中,检查当前的 bound 和目标是否符合要求,如果符合要求,继续判断:

 

function raiseEvent(e){

  if(isEnter(bound, box)){



   // 如果上次的区域和当前区域一样,表示在同区发生拖动, 应发生 dragover

    if( Drap.zone == zone)  {

        zone.trigger('dragover', e);

   } else {



       // 如果上次在一个zone,现在没有,表示离开一个 zone

      if(Drap.zone) Drap.zone.trigger('dragleave', e);



      Drap.zone = zone;  // 保存当前的 zone



     zone.trigger('dragenter', e);

     return;



  } 



}



   // 现在没有激活的区,但上次有,说明已经拖到上次的外面

  if(Drap.zone){

     Drap.zone.trigger('dragleave', e);

     Drap.zone = null;

    }



}

这样稍微加工,就可以完成 DragDrop 。

 

 

 

 

具体源码在以后一起发。

XULD QQ 744257564

你可能感兴趣的:(html5)