可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
We have a card game website that makes extensive use of jQuery Draggable & Droppable and which has worked nearly flawlessly (when using a mouse) for almost a year.
We would REALLY like to have the site work on touch screen devices, but we cannot seem to get jQuery's drag and especially drop functionality to work reliably.
Dragging works "ok" unless the div being dragged is inside another dom element with any kind of offset, margin, padding, etc. If it is, the dragged element is also offset from the user's finger by a similar amount. May not sound like a big deal, but it makes the interface unusuable.
Dropping just doesn't seem to work.
We've researched various options presented here on SO (will try to update this post with links to some of them if I can), but none work for us.
We've also researched jQuery Mobile but this is still in alpha and even so seems to be more of a framework for making a site emulate the UI of a phone vs what we're looking for.
Most of the SO and Google posts on this topic seem to trail off in late 2010 which makes me think there is an obvious answer that maybe we're just missing.
BTW, the functionality we're looking for is clearly technically possible because the YUI libraries for drag and drop work as expected. Unfortunatly, we can't justtify refactoring the site to switch from jQuery to YUI.
Anyone out there have any ideas? We would settle for a answer that supports only iPad, but it really needs to not require we refactor the existing site.
Thanks!
回答1:
Paste this at the beginning of your .js file:
(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);
Call me in the morning ;) (that's really arrogant, I didn't write this solution although I wish that I had, I'd reference it if I remember where I found it, if anyone know where this code came from please comment and credit that person)
UPDATE: Here you go: This is where I found this
回答2:
I suggest jQuery UI Touch Punch. I've tested it on iOS 5 and Android 2.3 and it works great on both.
回答3:
Old thread I know.......
Problem with the answer of @likwid_t is that it blocks also any input or other element that has to react on 'clicks' (for example inputs), so i wrote this solution. This solution made it possible to use any existing drag and drop library that is based upon mousedown, mousemove and mouseup events on any touch device (or cumputer). This is also a cross-browser solution.
I have tested in on several devices and it works fast (in combination with the drag and drop feature of ThreeDubMedia (see also http://threedubmedia.com/code/event/drag)). It is a jQuery solution so you can use it only with jQuery libs. I have used jQuery 1.5.1 for it because some newer functions don't work properly with IE9 and above (not tested with newer versions of jQuery).
Before you add any drag or drop operation to an event you have to call this function first:
simulateTouchEvents(<object>);
You can also block all components/children for input or to speed up event handling by using the following syntax:
simulateTouchEvents(<object>, true); // ignore events on childs
Here is the code i wrote. I used some nice tricks to speed up evaluating things (see code).
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;
};
What it does:
At first, it translates single touch events into mouse events. It checks if an event is caused by an element on/in the element that must be dragged around. If it is an input element like input, textarea etc, it skips the translation, or if a standard mouse event is attached to it it will also skip a translation.
Result:
Every element on a draggable element is still working.
Happy coding, greetz,
Erwin Haantjes
回答4:
I have created a jQuery plugin based on Erwinus' answer: https://github.com/RushPL/jquery.touch-mouse
回答5:
You can try this plugin but seems to work for iphone, ipod and ipad. Not sure if solves you're problem. Can be a specific ...
http://code.google.com/p/jquery-ui-for-ipad-and-iphone/
But android still looking for a solution.
Let me know if it helps. Regards Ricardo Rodrigues
回答6:
LikWidT has the simplest solution hands down from the website referenced. It would be great if any of the JQuery UI programmers could add this code or similar to their package. Jquery is certainly the simplest package to build drag/drop content for web developers... this is unfortunately a major flaw with nearly all devices having touch screens nowdays. I am now coding on a Surface Pro which is opening my eyes to these issues personally.
Just to reference the website again:
https://github.com/furf/jquery-ui-touch-punch
Edit: Also to clarify how simple this fix is. I had to first ensure I re-ordered my include files such that JQuery Javascript file was first then Jquery UI Javascript then my CSS Files. Then I just copy/pasted below the include files the Javascript code in the post above and that was it. I modified no code it is simply a function that looks for any touches in real time and converts them to equivalent mouse actions. Hence my above assertions for JQuery coders.
回答7:
Given worked for me :
eventAfterRender: function (event, element, view ) {
element.draggable();
},
回答8:
Tested on HTC One M8 under Android 6.13 / samsung Galaxy tab S2
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 ;
}