Javascript Arraste e solte para dispositivos touch [fechado]

120

Estou procurando um plug-in drag & DROP que funcione em dispositivos touch.

Gostaria de funcionalidade semelhante ao plugin jQuery UI, que permite elementos "droppable".

O plugin jqtouch suporta arrastar, mas não soltar.

Aqui está o recurso de arrastar e soltar que suporta apenas iPhone / iPad.

Alguém pode me apontar na direção de um plug-in de arrastar e soltar que funciona no android / ios?

... Ou pode ser possível atualizar o plugin jqtouch para droppability, ele já roda no Andriod e no IOS.

Obrigado!

Joe
fonte
1
Isso está em andamento, mas não sei quais dispositivos o suportam: Este plugins.jquery.com/project/mobiledraganddrop ... você consultou as bibliotecas do jQuerymobile.com? Eu também encontrei esta pergunta SO duplicado: stackoverflow.com/questions/3172100/...
iivel
Obrigado. Sim, o mobiledraganddrop suporta apenas cliques e soltos em dispositivos móveis. Não encontrei nada no jQuerymobile.com. A outra pergunta tem uma resposta já marcada como correta que se refere a sencha.com/products/touch que possui uma licença de fonte limitada.
joe
Estou curioso por um que funcione em navegadores móveis e de desktop.
Lime

Respostas:

258

Você pode usar a interface do usuário do Jquery para arrastar e soltar com uma biblioteca adicional que converte os eventos do mouse em toque, e é disso que você precisa. A biblioteca que eu recomendo é https://github.com/furf/jquery-ui-touch-punch , com este seu arrastar e soltar da interface do usuário do Jquery deve funcionar em aparelhos de toque

ou você pode usar esse código que estou usando, também converte os eventos do mouse em contato e funciona como mágica.

function touchHandler(event) {
    var touch = event.changedTouches[0];

    var simulatedEvent = document.createEvent("MouseEvent");
        simulatedEvent.initMouseEvent({
        touchstart: "mousedown",
        touchmove: "mousemove",
        touchend: "mouseup"
    }[event.type], true, true, window, 1,
        touch.screenX, touch.screenY,
        touch.clientX, touch.clientY, false,
        false, false, false, 0, null);

    touch.target.dispatchEvent(simulatedEvent);
    event.preventDefault();
}

function init() {
    document.addEventListener("touchstart", touchHandler, true);
    document.addEventListener("touchmove", touchHandler, true);
    document.addEventListener("touchend", touchHandler, true);
    document.addEventListener("touchcancel", touchHandler, true);
}

E no seu document.ready basta chamar a função init ()

código encontrado aqui

ryuutatsuo
fonte
11
Obrigado, no meu dispositivo Android agora é arrastável. No entanto, o evento click não é mais acionado quando clico nele. Alguma idéia de como consertar isso?
John Landheer
9
Nota: Desde o ouvinte de evento está registrado para todo o documento, esta solução também desabilita a rolagem no meu Nexus S ...
Ethan Leroy
29
Obrigado por compartilhar isso. No entanto, você deve dar crédito ao autor original do código que você postou. ross.posterous.com/2008/08/19/iphone-touch-events-in-javascript
undefined
2
@JohnLandheer eu corrigiu o problema, anexando os ouvintes de eventos apenas para os objetos que eu queria draggable,document.getElementById('draggableContainer').addEventListener(...
chiliNUT
1
Touch-punch é ótimo. Uma daquelas coisas "simplesmente funciona". Infelizmente, ele não suporta o toque duplo ... o que eu adoraria ver.
DA.
21

Para quem quer usar isso e manter a funcionalidade 'clique' (como John Landheer menciona em seu comentário), você pode fazer isso com apenas algumas modificações:

Adicione algumas globais:

var clickms = 100;
var lastTouchDown = -1;

Em seguida, modifique a instrução switch do original para isso:

var d = new Date();
switch(event.type)
{
    case "touchstart": type = "mousedown"; lastTouchDown = d.getTime(); break;
    case "touchmove": type="mousemove"; lastTouchDown = -1; break;        
    case "touchend": if(lastTouchDown > -1 && (d.getTime() - lastTouchDown) < clickms){lastTouchDown = -1; type="click"; break;} type="mouseup"; break;
    default: return;
}

Você pode ajustar os 'cliques' ao seu gosto. Basicamente, é só procurar um 'touchstart' seguido rapidamente por um 'touchend' para simular um clique.

EZ Hart
fonte
@EZ Hart - por favor, deixe-me saber onde colocar seu código acima, para fornecer um evento de clique ???
Valay
1
@ChakoDesai - O código na resposta foi muito editado desde que escrevi minha resposta. Confira stackoverflow.com/posts/6362527/revisions e veja o código de 30 de junho de 2011; minha resposta fará muito mais sentido com base nessa versão.
EZ Hart
@EZ Hart - Atualizei meu código a partir do URL fornecido. Mas por que às vezes clickfunciona e às vezes não ???
Valay
@ ChakoDesai - Sem ver seu código, não tenho certeza. Você pode abrir uma nova pergunta para isso.
EZ Hart
Uma resposta atualizada para fazer o código acima funcionar com eventos de clique pode ser encontrada aqui: stackoverflow.com/questions/28218888/…
Blunderfest 02/02/2015
12

Obrigado pelos códigos acima! - Tentei várias opções e esse foi o ingresso. Eu tive problemas em que preventDefault estava impedindo a rolagem no ipad - agora estou testando itens arrastáveis ​​e funciona muito bem até agora.

if (event.target.id == 'draggable_item' ) {
    event.preventDefault();
}
gregpress
fonte
Você já testou isso no Windows Phone? Ou qualquer outra coisa que não seja o iPhone? De experiências anteriores, isso parece funcionar perfeitamente em iPhones / iPads, mas não funciona bem em outros dispositivos, especialmente em Windows Phones.
quase um iniciante
10

Eu tinha a mesma solução que a resposta do gregpress , mas meus itens arrastáveis ​​usavam uma classe em vez de um ID. Parece funcionar.

var $target = $(event.target);  
if( $target.hasClass('draggable') ) {  
    event.preventDefault();  
}
Eric
fonte
4
O fato de você ter simplesmente usado um seletor diferente não garante ser uma resposta separada, mas você deveria ter comentado a resposta do @ gregpress.
bPratik
2
@bPratik, a menos que ele queira uma formatação melhor que uma resposta for fornecida - e o fato de ele ter fornecido um exemplo de código inteiro justifica uma resposta separada. Deveria ter deixado um comentário ligando para sua resposta embora ...
drzaus
8

Fio velho que eu sei .......

O problema com a resposta do @ryuutatsuo é que ele bloqueia também qualquer entrada ou outro elemento que precise reagir com 'cliques' (por exemplo, entradas), então escrevi esta solução. Essa solução possibilitou o uso de qualquer biblioteca de arrastar e soltar existente baseada em eventos de remoção de mouse, remoção de mouse e mouse em qualquer dispositivo de toque (ou cumputador). Essa também é uma solução para vários navegadores.

Eu testei em vários dispositivos e funciona rápido (em combinação com o recurso de arrastar e soltar do ThreeDubMedia (consulte também http://threedubmedia.com/code/event/drag )). É uma solução jQuery para que você possa usá-lo apenas com bibliotecas jQuery. Eu usei o jQuery 1.5.1 para isso porque algumas funções mais recentes não funcionam corretamente com o IE9 e superior (não testadas com versões mais recentes do jQuery).

Antes de adicionar qualquer operação de arrastar ou soltar em um evento, você deve chamar esta função primeiro :

simulateTouchEvents(<object>);

Você também pode bloquear todos os componentes / filhos para entrada ou acelerar a manipulação de eventos usando a seguinte sintaxe:

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

Aqui está o código que escrevi. Usei alguns truques legais para acelerar a avaliação das coisas (consulte o código).

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;
}; 

O que faz: no início, converte eventos de toque único em eventos de mouse. Ele verifica se um evento é causado por um elemento no / no elemento que deve ser arrastado. Se for um elemento de entrada como input, textarea etc, pulará a tradução ou, se um evento de mouse padrão estiver anexado, também pulará uma tradução.

Resultado: todos os elementos de um elemento arrastável ainda estão funcionando.

Feliz codificação, greetz, Erwin Haantjes

Codebeat
fonte
qual objeto devo passar simulateTouchEvents(<object>, true);???
Valay
Por exemplo: simulateTouchEvents ($ ('# yourid;), true); ou simulateTouchEvents (document.getElementById ('yourid'), true); etc
Codebeat
você poderia, por favor, olhar para o meu outro link de pergunta ???
Valay
Use threedubmedia.com/code/event/drag e desative x ou y movendo-se do elemento. Quando você usa o código neste artigo, pode 'rolar' as barras de rolagem. Mas saiba por que você deseja fazer isso porque uma página no celular já possui barras de rolagem. Não entenda o que você quer fazer com isso. Sucesso!
Codebeat
Eu tenho que adicionar drag-n-drop de colunas e rolagem de ambos. Quando ligo toucheventos chrome, não consigo rolar a tabela. Nem mesmo no celular.
Valay #