65.9K
CodeProject 正在变化。 阅读更多。
Home

在 jQuery-ui draggable 在移动浏览器上失败时进行拖放!

starIconstarIconstarIconstarIconstarIcon

5.00/5 (4投票s)

2016年10月25日

CPOL

4分钟阅读

viewsIcon

23776

本文描述了当 jQuery-ui 和 touch-punch 库失败时(当项目使用 transform-origin 或其他坐标转换时)可以使用的另一种拖放方法。

引言

这是我在 CodeProject 上的第四篇文章,我希望您能喜欢它,因为在下面的段落中,我想描述并处理一个网络开发人员一生中只会遇到几次的缺点!

jQuery、jQuery-ui 和 touch-pouch 库可以被认为是桌面和移动浏览器中拖放操作的默认标准。这是因为这三个库允许忽略拖放操作的所有复杂性,只需调用一个方法:$.draggable(),它通知 jQuery 子系统一个对象可以被拖动。

$.draggable 方法可以用 drop: function (event,ui) {} 参数来修饰,我们可以在其中添加处理 drop 事件的代码。

这看起来很完美!但是,当我们使用一些新的 CSS3 功能时会发生什么?

背景

当我们在高响应环境中使用时,我们可以使用**转换**,例如 transform-coordinatetransform:scale()transform:rotate 等等。似乎 jQuery **不太喜欢**这种现象,并且在某些情况下,**它可能会在某些操作中犯错误**。

对于这篇文章,我选择了 HYPE3TUMULT,它们允许以自动方式处理重新缩放和调整大小。我准备了两个例子来展示这些错误。

在下面的图片中,您可以查看通过 HYPE 引擎在不同设备上调整大小和重新缩放的相同对象,而无需任何用户代码。

桌面浏览器视图

Iphone 横向和纵向视图

正如您所看到的,所有三个视图看起来都相同(根据视口大小重新缩放)。

但是,我想邀请您在不同的浏览器上玩 demo1。您可以尝试拖放会失败,因为**拖动恢复会错误地返回横向和桌面浏览器中的坐标**(原始位置将不会被尊重)。

我不确定这种问题的复发率,但我可以确认,当使用坐标转换函数时,会出现此问题。**请注意,DEMO1 仅使用 jQuery、jQuery-ui 和 touch-pouch 库,而不使用原生拖放支持。**

Using the Code

我认为可拖动恢复问题在于 jQuery-ui 的实现,但我不确定。所以,我的想法是放弃 jQuery-ui 和 pouch-touch 库,并使用

  • 原生桌面浏览器拖放(Chrome、Firefox、Opera、Safari 和 Edge 支持它)
  • 用于移动浏览器拖放功能的触摸事件

桌面浏览器原生支持

这种方法的第一个步骤必须是将一个类或唯一 ID 分配给我们要使其可拖动的每个对象。在我的例子中,所有彩色正方形都被命名为 c1c2... c12 并且具有类名 gameObject。因此,我只需使用以下代码启用原生拖动功能。

   for (var c=1;c<=12;c++)
   {
       var e = document.getElementById("c"+c);
       $("#c"+c).attr("draggable","true");
       $("#c"+c).attr("ondragstart","_dragStart(event)");
       $("#c"+c).attr("ondrop","_onDrop(event)");
       $("#c"+c).attr("ondragover","_onDragOver(event)");
   }

为了简单起见,我报告了在单独的代码块中处理拖放的三个函数

     function _dragStart(a)
     {
         a.dataTransfer.setData("text", a.target.id);
     }

     function _onDrop(e)
     {
       e.preventDefault();
       var src = e.dataTransfer.getData("text");
       var dst = e.target.id;
       // here you can do what you want with source and destination of drag and drop !
     }

      function _onDragOver(a)
      {     
        a.preventDefault();
      }

使用触摸的移动浏览器拖放

如今,移动浏览器不实现对拖放的原生支持。因此,第二步是处理代表触摸屏上的拖放操作的三个手势:touchstarttouchmovetouchend

所有拖放操作都使用一个阴影(又名 ghost)图像来帮助操作。该图像将显示在光标附近,以便向用户显示哪些对象正在移动。我们还需要跟踪对象的起始位置,以便恢复拖放。

以下三个变量可以帮助我们进行触摸!您可以尝试 DEMO2 来尝试这种方法。

 // touch capability
 var startPos=[];
 var toDrag = null;
 var dragStart = false;

然后,对于屏幕上的每个**触摸**,我们需要了解用户是否点击了可拖动对象。这可以通过简单的碰撞检测来完成。

  $(document).on("touchstart",function(e) {
     e.preventDefault();
     // touch coordinates
     var xPos = e.originalEvent.touches[0].pageX;
     var yPos = e.originalEvent.touches[0].pageY;

     startPos[0]=xPos;
     startPos[1]=yPos;

     $(".gameobject").each(function(index)
     {
         var jx = parseFloat($(this).offset().left);
         var jy = parseFloat($(this).offset().top);
         var jw = parseFloat($(this).width());
         var jh = parseFloat($(this).height());
        
         //collision detect
         if (jx <= xPos && jy <= yPos && xPos <= (jx+jw) && yPos <= (jy+jh))
         {
            if ($(this).attr("draggable")=="false")
            {
              //object touched is not draggable! 
            }
            else {
                 // collision detected
                 toDrag = $(this).attr("id");
                 dragStart=true;
                 // setting up shadow image
                 var shadow = document.getElementById("shadow");
                 if (shadow==null)
                 {
                     shadow = document.createElement("div");
                     document.getElementById("game").appendChild(shadow);
                     shadow.setAttribute("id","shadow");
                     shadow.style.position="absolute";
                     shadow.style.zIndex="9999999";
                 }
                    // for the purpose of this article ghost image will be a square of
                    // the same color of touched object
                    $("#shadow").css("visibility","visible");
                    var shadowImg = $(this).css("background-image");
                    $("#shadow").css("background-image",shadowImg);
                    $("#shadow").css("background-size","100% 100%");
                    $("#shadow").css("left",xPos+"px");
                    $("#shadow").css("top",yPos+"px");
                    $("#shadow").css("width",jw+"px");
                    $("#shadow").css("height",jh+"px");
                    return;
               }
            }
          });
        });

现在,我们检测到可拖动对象上的碰撞,因此我们需要通过跟踪任何其他触摸来跟踪用户的手指。这可以通过几行代码来完成。

$(document).on("touchmove",function(e) {
    e.preventDefault();
    if (dragStart && toDrag!=null)
    {
          // move the shadow
          var xPos = e.originalEvent.touches[0].pageX;
          var yPos = e.originalEvent.touches[0].pageY;
          var sw = parseFloat($("#shadow").width());
          var sh = parseFloat($("#shadow").height());
          $("#shadow").css("left",(xPos-sw/2)+"px");
          $("#shadow").css("top",(yPos-sh/2)+"px");
     }
});

最后,我们需要了解手指离开屏幕的位置。这将是我们阴影图像的最后一个坐标,也就是**放置位置**。

  $(document).on("touchend",function(e) {
   e.preventDefault();
   if (dragStart && toDrag!=null)
   {
         //here you can apply graphics effect on shadow like revert to initial pos or fade out
         $("#shadow").css("visibility","hidden");
         dragStart=false;

         var xPos = 0;
         var yPos = 0;

         if (e.changedTouched==undefined)
         {
                xPos = e.originalEvent.changedTouches[0].pageX;
                yPos = e.originalEvent.changedTouches[0].pageY;
         }
         else
         {
                xPos = e.changedTouches[0].pageX;
                yPos = e.changedTouched[0].pageY;
         }
         // looking for collision between gameObject and touchleave position
         var target = null;
         $(".gameobject").each(function(index) {
           var tx = parseFloat($(this).offset().left);
           var ty = parseFloat($(this).offset().top);
           var tw = parseFloat($(this).width());
           var th = parseFloat($(this).height());

           if (tx <= xPos && ty <= yPos && xPos <= (tx+tw) && yPos <= (ty+th))
           {
               target = $(this).attr("id");
               //here you can execute code on source and target
               return;
           }
           }).promise().done(function() { });
           }
     });
}

关注点

如果有人知道可以解决此问题的 jQuery-ui 配置参数,那么这篇文章可能毫无用处。我不知道任何方法,但我不确定是否存在一种方法。

历史

  • 英语改进(感谢 Natascia Spada)@ 2016/10/27 - 12:18
  • 发布于 @ 2016/10/25 - 15:00
© . All rights reserved.