触摸设备上的jQuery拖放(iPad,Android)

时间:2011-04-26 20:33:07

标签: jquery android jquery-ui touch ipod-touch

我们有一个卡片游戏网站,广泛使用jQuery Draggable& Droppable和近乎完美无缺的(当使用鼠标时)近一年。

我们真的希望网站能够在触摸屏设备上运行,但我们似乎无法获得jQuery的拖拽,尤其是降低功能以便可靠地工作。

拖动工作“ok”,除非被拖动的div位于具有任何偏移,边距,填充等的另一个dom元素内。如果是,则拖动的元素也会偏离用户的手指相似的量。可能听起来不是什么大不了的事,但它使界面变得不可用。

放弃似乎不起作用。

我们已经研究了SO上提供的各种选项(如果可以的话,会尝试更新这篇文章的链接,但是没有一个适合我们。

我们也研究过jQuery Mobile,但这仍然是alpha版本,甚至更像是一个框架,让网站模仿手机的UI与我们正在寻找的东西。

关于这个主题的大部分SO和Google帖子似乎都在2010年末落后,这让我觉得有一个明显的答案,也许我们只是错过了。

顺便说一下,我们正在寻找的功能在技术上显而易见,因为用于拖放的YUI库按预期工作。不幸的是,我们不能仅仅重构网站以从jQuery切换到YUI。

那里有人有什么想法吗?我们会选择只支持iPad的答案,但它确实不需要我们重构现有网站。

谢谢!

8 个答案:

答案 0 :(得分:36)

将其粘贴到.js文件的开头:

(function ($) {
    // Detect touch support
    $.support.touch = 'ontouchend' in document;
    // Ignore browsers without touch support
    if (!$.support.touch) {
    return;
    }
    var mouseProto = $.ui.mouse.prototype,
        _mouseInit = mouseProto._mouseInit,
        touchHandled;

    function simulateMouseEvent (event, simulatedType) { //use this function to simulate mouse event
    // Ignore multi-touch events
        if (event.originalEvent.touches.length > 1) {
        return;
        }
    event.preventDefault(); //use this to prevent scrolling during ui use

    var touch = event.originalEvent.changedTouches[0],
        simulatedEvent = document.createEvent('MouseEvents');
    // Initialize the simulated mouse event using the touch event's coordinates
    simulatedEvent.initMouseEvent(
        simulatedType,    // type
        true,             // bubbles                    
        true,             // cancelable                 
        window,           // view                       
        1,                // detail                     
        touch.screenX,    // screenX                    
        touch.screenY,    // screenY                    
        touch.clientX,    // clientX                    
        touch.clientY,    // clientY                    
        false,            // ctrlKey                    
        false,            // altKey                     
        false,            // shiftKey                   
        false,            // metaKey                    
        0,                // button                     
        null              // relatedTarget              
        );

    // Dispatch the simulated event to the target element
    event.target.dispatchEvent(simulatedEvent);
    }
    mouseProto._touchStart = function (event) {
    var self = this;
    // Ignore the event if another widget is already being handled
    if (touchHandled || !self._mouseCapture(event.originalEvent.changedTouches[0])) {
        return;
        }
    // Set the flag to prevent other widgets from inheriting the touch event
    touchHandled = true;
    // Track movement to determine if interaction was a click
    self._touchMoved = false;
    // Simulate the mouseover event
    simulateMouseEvent(event, 'mouseover');
    // Simulate the mousemove event
    simulateMouseEvent(event, 'mousemove');
    // Simulate the mousedown event
    simulateMouseEvent(event, 'mousedown');
    };

    mouseProto._touchMove = function (event) {
    // Ignore event if not handled
    if (!touchHandled) {
        return;
        }
    // Interaction was not a click
    this._touchMoved = true;
    // Simulate the mousemove event
    simulateMouseEvent(event, 'mousemove');
    };
    mouseProto._touchEnd = function (event) {
    // Ignore event if not handled
    if (!touchHandled) {
        return;
    }
    // Simulate the mouseup event
    simulateMouseEvent(event, 'mouseup');
    // Simulate the mouseout event
    simulateMouseEvent(event, 'mouseout');
    // If the touch interaction did not move, it should trigger a click
    if (!this._touchMoved) {
      // Simulate the click event
      simulateMouseEvent(event, 'click');
    }
    // Unset the flag to allow other widgets to inherit the touch event
    touchHandled = false;
    };
    mouseProto._mouseInit = function () {
    var self = this;
    // Delegate the touch handlers to the widget's element
    self.element
        .on('touchstart', $.proxy(self, '_touchStart'))
        .on('touchmove', $.proxy(self, '_touchMove'))
        .on('touchend', $.proxy(self, '_touchEnd'));

    // Call the original $.ui.mouse init method
    _mouseInit.call(self);
    };
})(jQuery);

早上给我打电话;)(这真的很傲慢,我没有写这个解决方案,虽然我希望我有,如果我记得我发现它的地方,我会参考它,如果有人知道这个代码来自哪里请评论并表彰那个人)

更新:在这里:This is where I found this

答案 1 :(得分:16)

我建议jQuery UI Touch Punch。我已经在iOS 5和Android 2.3上测试了它,它在两者上都很好用。

答案 2 :(得分:4)

旧线程我知道.......

@likwid_t的答案问题在于它还会阻止任何输入或其他必须对“点击”做出反应的元素(例如输入),所以我写了这个解决方案。该解决方案使得可以在任何触摸设备(或cumputer)上使用基于mousedown,mousemove和mouseup事件的任何现有拖放库。这也是一个跨浏览器的解决方案。

我已经在多个设备上进行了测试,它运行速度很快(结合ThreeDubMedia的拖放功能(另请参阅http://threedubmedia.com/code/event/drag))。它是一个jQuery解决方案,因此您只能将它用于jQuery库。我已经使用了 jQuery 1.5.1 ,因为一些较新的函数无法在IE9及以上版本中正常工作(未使用较新版本的jQuery进行测试)。

之前您将拖放操作添加到事件您必须先调用此功能

simulateTouchEvents(<object>);

您还可以使用以下语法阻止所有组件/子项以进行输入或加速事件处理:

simulateTouchEvents(<object>, true); // ignore events on childs

这是我写的代码。我使用了一些不错的技巧来加速评估事物(见代码)。

function simulateTouchEvents(oo,bIgnoreChilds)
{
 if( !$(oo)[0] )
  { return false; }

 if( !window.__touchTypes )
 {
   window.__touchTypes  = {touchstart:'mousedown',touchmove:'mousemove',touchend:'mouseup'};
   window.__touchInputs = {INPUT:1,TEXTAREA:1,SELECT:1,OPTION:1,'input':1,'textarea':1,'select':1,'option':1};
 }

$(oo).bind('touchstart touchmove touchend', function(ev)
{
    var bSame = (ev.target == this);
    if( bIgnoreChilds && !bSame )
     { return; }

    var b = (!bSame && ev.target.__ajqmeclk), // Get if object is already tested or input type
        e = ev.originalEvent;
    if( b === true || !e.touches || e.touches.length > 1 || !window.__touchTypes[e.type]  )
     { return; } //allow multi-touch gestures to work

    var oEv = ( !bSame && typeof b != 'boolean')?$(ev.target).data('events'):false,
        b = (!bSame)?(ev.target.__ajqmeclk = oEv?(oEv['click'] || oEv['mousedown'] || oEv['mouseup'] || oEv['mousemove']):false ):false;

    if( b || window.__touchInputs[ev.target.tagName] )
     { return; } //allow default clicks to work (and on inputs)

    // https://developer.mozilla.org/en/DOM/event.initMouseEvent for API
    var touch = e.changedTouches[0], newEvent = document.createEvent("MouseEvent");
    newEvent.initMouseEvent(window.__touchTypes[e.type], true, true, window, 1,
            touch.screenX, touch.screenY,
            touch.clientX, touch.clientY, false,
            false, false, false, 0, null);

    touch.target.dispatchEvent(newEvent);
    e.preventDefault();
    ev.stopImmediatePropagation();
    ev.stopPropagation();
    ev.preventDefault();
});
 return true;
}; 

它的作用: 首先,它将单个触摸事件转换为鼠标事件。它检查事件是否由必须拖动的元素上/中的元素引起。如果它是输入元素,例如input,textarea等,它会跳过翻译,或者如果附加了标准鼠标事件,它也会跳过翻译。

结果: 可拖动元素上的每个元素仍然有效。

快乐的编码,greetz, Erwin Haantjes

答案 3 :(得分:3)

我创建了一个基于Erwinus答案的jQuery插件:https://github.com/RushPL/jquery.touch-mouse

答案 4 :(得分:0)

你可以试试这个插件但似乎适用于iphone,ipod和ipad。不确定是否解决了你的问题。可以是具体的......

http://code.google.com/p/jquery-ui-for-ipad-and-iphone/

但是android仍在寻找解决方案。

如果有帮助,请告诉我。关心里卡多罗德里格斯

答案 5 :(得分:0)

LikWidT从所引用的网站上获得最简单的解决方案。如果任何JQuery UI程序员可以将这些代码或类似代码添加到他们的包中,那就太好了。 Jquery当然是为Web开发人员构建拖放内容的最简单的软件包......不幸的是,这是几乎所有设备都具有触摸屏的一个主要缺陷。我现在正在使用Surface Pro进行编码,这个问题让我亲眼目睹了这些问题。

再次引用该网站: https://github.com/furf/jquery-ui-touch-punch

编辑:还要澄清此修复程序的简单程度。我必须首先确保我重新订购我的包含文件,以便JQuery Javascript文件首先是Jquery UI Javascript然后我的CSS文件。然后我只是在上面的帖子中复制/粘贴包含文件Javascript代码,就是这样。我没有修改代码它只是一个实时查找任何触摸并将它们转换为等效鼠标操作的函数。因此,我对JQuery编码器的上述断言。

答案 6 :(得分:0)

鉴于我的工作:

eventAfterRender: function (event, element, view ) {
         element.draggable();
},

答案 7 :(得分:0)

在Android 6.13 / samsung Galaxy标签S2下测试HTC One M8

function simulateMouseEvent (event, simulatedType) { //use this function to simulate mouse event

// restriction to preserve input use
    window.__touchInputs = {INPUT:1,TEXTAREA:1,SELECT:1,OPTION:1,'input':1,'textarea':1,'select':1,'option':1};
    if( window.__touchInputs[event.target.tagName] ) return ;

}