zoukankan      html  css  js  c++  java
  • (十) 模拟 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

  • 相关阅读:
    简单的三栏,文字多行居中效果 css原生
    目录
    HttpRunner使用
    测试职能
    缺陷
    SQL操作数据
    jmeter使用
    接口自动化理论引入
    接口自动化框架(Pytest,Allure,Yaml)
    jmeter 登陆--查询存在否-->新建客户-->查询存在否 + 压测
  • 原文地址:https://www.cnblogs.com/xuld/p/1943320.html
Copyright © 2011-2022 走看看