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





5.00/5 (4投票s)
本文描述了当 jQuery-ui 和 touch-punch 库失败时(当项目使用 transform-origin 或其他坐标转换时)可以使用的另一种拖放方法。
引言
这是我在 CodeProject 上的第四篇文章,我希望您能喜欢它,因为在下面的段落中,我想描述并处理一个网络开发人员一生中只会遇到几次的缺点!
jQuery、jQuery-ui 和 touch-pouch 库可以被认为是桌面和移动浏览器中拖放操作的默认标准。这是因为这三个库允许忽略拖放操作的所有复杂性,只需调用一个方法:$.draggable()
,它通知 jQuery 子系统一个对象可以被拖动。
$.draggable
方法可以用 drop: function (event,ui) {}
参数来修饰,我们可以在其中添加处理 drop 事件的代码。
这看起来很完美!但是,当我们使用一些新的 CSS3 功能时会发生什么?
背景
当我们在高响应环境中使用时,我们可以使用**转换**,例如 transform-coordinate
、transform:scale()
、transform:rotate
等等。似乎 jQuery **不太喜欢**这种现象,并且在某些情况下,**它可能会在某些操作中犯错误**。
对于这篇文章,我选择了 HYPE3 和 TUMULT,它们允许以自动方式处理重新缩放和调整大小。我准备了两个例子来展示这些错误。
在下面的图片中,您可以查看通过 HYPE
引擎在不同设备上调整大小和重新缩放的相同对象,而无需任何用户代码。
桌面浏览器视图
Iphone 横向和纵向视图
正如您所看到的,所有三个视图看起来都相同(根据视口大小重新缩放)。
但是,我想邀请您在不同的浏览器上玩 demo1。您可以尝试拖放会失败,因为**拖动恢复会错误地返回横向和桌面浏览器中的坐标**(原始位置将不会被尊重)。
我不确定这种问题的复发率,但我可以确认,当使用坐标转换函数时,会出现此问题。**请注意,DEMO1 仅使用 jQuery、jQuery-ui 和 touch-pouch 库,而不使用原生拖放支持。**
Using the Code
我认为可拖动恢复问题在于 jQuery-ui 的实现,但我不确定。所以,我的想法是放弃 jQuery-ui 和 pouch-touch 库,并使用
- 原生桌面浏览器拖放(Chrome、Firefox、Opera、Safari 和 Edge 支持它)
- 用于移动浏览器拖放功能的触摸事件
桌面浏览器原生支持
这种方法的第一个步骤必须是将一个类或唯一 ID 分配给我们要使其可拖动的每个对象。在我的例子中,所有彩色正方形都被命名为 c1
、c2
... 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();
}
使用触摸的移动浏览器拖放
如今,移动浏览器不实现对拖放的原生支持。因此,第二步是处理代表触摸屏上的拖放操作的三个手势:touchstart
、touchmove
和 touchend
。
所有拖放操作都使用一个阴影(又名 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