Como posso tornar um div jQuery UI 'draggable ()' arrastável para touchscreen?

112

Eu tenho uma interface de usuário jQuery draggable()que funciona no Firefox e no Chrome. O conceito de interface do usuário é basicamente clicar para criar um item do tipo "post-it".

Basicamente, eu clico ou toco em div#everything(100% alto e largo) que escuta os cliques e uma área de texto de entrada é exibida. Você adiciona texto e, quando terminar, ele o salva. Você pode arrastar este elemento. Isso funciona em navegadores normais, mas em um iPad com o qual posso testar, não consigo arrastar os itens. Se eu tocar para selecionar (então escurece um pouco), não posso arrastá-lo. Não vai arrastar para a esquerda ou direita de forma alguma. I pode arrastar para cima ou para baixo, mas eu não estou arrastando o indivíduo div, estou arrastando toda a página.

Então, aqui está o código que uso para capturar cliques:

$('#everything').bind('click', function(e){
    var elem = document.createElement('DIV');
    STATE.top = e.pageY;
    STATE.left = e.pageX;
    var e = $(elem).css({
        top: STATE.top,
        left: STATE.left
    }).html('<textarea></textarea>')
    .addClass('instance')
    .bind('click', function(event){
        return false;
    });
    $(this).append(e);
});

E aqui está o código que uso para "salvar" a nota e transformar a div de entrada em apenas uma div de exibição:

$('textarea').live('mouseleave', function(){
    var val = jQuery.trim($(this).val());
    STATE.content = val;
    if (val == '') {
        $(this).parent().remove();
    } else {
        var div  = $(this).parent();
        div.text(val).css({
            height: '30px'
        });
        STATE.height = 30;
        if ( div.width() !== div[0].clientWidth || div.height () !== div[0].clientHeight ) {
            while (div.width() !== div[0].clientWidth || div.height () !== div[0].clientHeight) {
                var h = div.height() + 10;
                STATE.height = h;
                div.css({
                    height: (h) + 'px'
                });     // element just got scrollbars
            }
        }
        STATE.guid = uniqueID()
        div.addClass('savedNote').attr('id', STATE.guid).draggable({
            stop: function() {
                var offset = $(this).offset();
                STATE.guid = $(this).attr('id');
                STATE.top = offset.top;
                STATE.left = offset.left;
                STATE.content = $(this).text();
                STATE.height = $(this).height();
                STATE.save();
            }
        });
        STATE.save();
        $(this).remove();
    }
});

E eu tenho este código quando carrego a página de notas salvas:

$('.savedNote').draggable({
    stop: function() {
        STATE.guid = $(this).attr('id');
        var offset = $(this).offset();
        STATE.top = offset.top;
        STATE.left = offset.left;
        STATE.content = $(this).text();
        STATE.height = $(this).height();
        STATE.save();
    }
});

Meu STATEobjeto lida com salvar as notas.

Onload, este é todo o corpo html:

<body> 
    <div id="everything"></div> 
<div class="instance savedNote" id="iddd1b0969-c634-8876-75a9-b274ff87186b" style="top:134px;left:715px;height:30px;">Whatever dude</div> 
<div class="instance savedNote" id="id8a129f06-7d0c-3cb3-9212-0f38a8445700" style="top:131px;left:347px;height:30px;">Appointment 11:45am</div> 
<div class="instance savedNote" id="ide92e3d13-afe8-79d7-bc03-818d4c7a471f" style="top:144px;left:65px;height:80px;">What do you think of a board where you can add writing as much as possible?</div> 
<div class="instance savedNote" id="idef7fe420-4c19-cfec-36b6-272f1e9b5df5" style="top:301px;left:534px;height:30px;">This was submitted</div> 
<div class="instance savedNote" id="id93b3b56f-5e23-1bd1-ddc1-9be41f1efb44" style="top:390px;left:217px;height:30px;">Hello world from iPad.</div> 

</body>

Então, minha pergunta é: como posso fazer isso funcionar melhor no iPad?

Não estou configurado no jQuery UI, estou me perguntando se isso é algo que estou fazendo de errado com o jQuery UI ou jQuery, ou se pode haver melhores estruturas para fazer elementos draggable () compatíveis entre plataformas / versões anteriores que irão funcionam para interfaces de usuário com tela de toque.

Comentários mais gerais sobre como escrever componentes de interface do usuário como este também são bem-vindos.

Obrigado!


ATUALIZAÇÃO: consegui simplesmente encadear isso em minha draggable()chamada de interface do usuário do jQuery e obter a capacidade de arrastar correta no iPad!

.touch({
    animate: false,
    sticky: false,
    dragx: true,
    dragy: true,
    rotate: false,
    resort: true,
    scale: false
});

O plugin jQuery Touch fez o truque!

Artlung
fonte
1
Estou curioso sobre uma coisa: você pode arrastar o div com dois ou três dedos? Eu sei que às vezes você precisa usar vários dedos para rolar o conteúdo incorporado no Safari para celular, então pode ser o mesmo para conteúdo "arrastável".
Walter Mundt
Walter Mundt obrigado! Não tentei nenhuma variação de dedos, vou tentar quando chegar em minhas mãos!
artlung de
1
dois ou três dedos, na verdade, impediram que a "página inteira" rolasse inadvertidamente, mas não fizeram nenhuma alteração para arrastar.
artlung
Essa técnica não pareceu funcionar para mim, infelizmente. :(
blaster
@blaster Você precisará olhar algumas das outras respostas para outras soluções possíveis
artlung

Respostas:

138

Depois de perder muitas horas, me deparei com isso!

jquery-ui-touch-punch

Ele traduz eventos de toque como eventos de clique. Lembre-se de carregar o script após jquery.

Eu tenho isso funcionando no iPad e iPhone

$('#movable').draggable({containment: "parent"});
ctrl-alt-dileep
fonte
2
Esta solução funciona muito bem, outra resposta que eu cansei estava
cheia de
Uma pequena dica: funciona muito bem, embora se o elemento arrastável coberto por camadas como uma imagem com uma máscara acima dele, nenhum arrastar será ativado, mas a solução será adicionar eventos de ponteiro: nenhum; nas camadas superiores.
Adler
Esta é uma solução ótima e simples, basta usar o plugin e continuar trabalhando com a função arrastável do JQuery. Perfeito, obrigado!
quase um iniciante em
Isso impedirá itens clicáveis ​​dentro do arrastável.
Abdul Sadik Yalcin
61

Cuidado: esta resposta foi escrita em 2010 e a tecnologia avança rapidamente. Para uma solução mais recente, veja a resposta de @ctrl-alt-dileep abaixo .


Dependendo de suas necessidades, você pode experimentar o plugin jQuery touch ; você pode tentar um exemplo aqui . Funciona bem arrastar no meu iPhone, enquanto o jQuery UI Draggable não.

Alternativamente, você pode tentar este plug - in, embora isso possa exigir que você realmente escreva sua própria função arrastável.

Como nota: acredite ou não, estamos ouvindo um burburinho crescente sobre como os dispositivos de toque, como o iPad e o iPhone, estão causando problemas tanto para sites que usam: funções hover / onmouseover e conteúdo arrastável.

Se você estiver interessado na solução subjacente para isso, use três novos eventos JavaScript; ontouchstart, ontouchmove e ontouchend. Na verdade, a Apple escreveu um artigo sobre seu uso, que você pode encontrar aqui . Um exemplo simplificado pode ser encontrado aqui . Esses eventos são usados ​​em ambos os plug-ins aos quais vinculei.

Vonconrad
fonte
2
Super incrível! Tudo que eu tive que fazer foi ligar .touch({ animate: false, sticky: false, dragx: true, dragy: true, rotate: false, resort: true, scale: false });para a minha draggable()chamada existente e funcionou muito bem! Ainda tenho que trabalhar todos os eventos com os quais quero lidar para obter o fluxo de trabalho certo, mas o plugin jQuery touch resolveu!
artlung
4
o plugin parece não estar mais disponível em jquery.com. você ainda pode encontrar o javascript aqui manifestinteractive.com/iphone/touch/js/jquery.touch.js
bjelli
1
Heh, agora o plug-in também está faltando em manifestinteractive.com. Experimente: plugins.jquery.com/files/jquery.touch.js.txt
Ian Hunter
5
esta resposta não é mais válida. veja a resposta de @ ctrl-alt-dileep abaixo (jquery-ui-touch-punch) para uma resposta de 2012
bjelli
1
@bjelli Obrigado por apontar isso. Eu atualizei minha resposta com um aviso. :)
vonconrad
24

Este projeto deve ser útil - mapas de eventos de toque para clicar em eventos de uma forma que permite que a IU do jQuery funcione no iPad e no iPhone sem nenhuma alteração. Basta adicionar o JS a qualquer projeto existente.

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

Steve
fonte
7

O jQuery ui 1.9 vai cuidar disso para você. Aqui está uma demonstração do pré:

https://dl.dropbox.com/u/3872624/lab/touch/index.html

Basta pegar o jquery.mouse.ui.js, colocá-lo sob o arquivo jQuery ui que você está carregando, e isso é tudo que você deve fazer! Funciona para classificáveis ​​também.

Este código está funcionando muito bem para mim, mas se você está recebendo erros, uma versão atualizada de jquery.mouse.ui.js pode ser encontrada aqui:

Jquery-ui sortable não funciona em dispositivos de toque baseados em Android ou IOS

aquele meio caminho
fonte
3
Isso é ótimo que eles estão lidando com isso 1.9. FWIW, descobri que a versão do código naquele demo tinha bugs e não funcionava muito bem. Alguém postou uma versão mais correta sobre esta questão: stackoverflow.com/questions/6745098/… isso está funcionando melhor para mim.
asgeo1
Eu atualizei minha resposta para resolver isso. Ainda não recebi nenhum erro no meu caso de uso com o original.
thatmiddleway
1
O link da caixa de depósito está desativado.
BerggreenDK
2

Eu estava lutando com um problema semelhante ontem. Eu já tinha uma solução "funcionando" usando o jQuery UI's draggable junto com o jQuery Touch Punch, que são mencionados em outras respostas. No entanto, usar este método estava causando bugs estranhos em alguns dispositivos Android para mim e, portanto, decidi escrever um pequeno plugin jQuery que pode tornar os elementos HTML arrastáveis ​​usando eventos de toque em vez de usar um método que emula eventos de mouse falsos.

O resultado disso é o jQuery Draggable Touch, que é um plugin jQuery simples para fazer elementos arrastáveis, que tem dispositivos de toque como seu alvo principal usando eventos de toque (como touchstart, touchmove, touchend, etc.). Ele ainda tem um fallback que usa eventos de mouse se o navegador / dispositivo não suportar eventos de toque.

E aí cara
fonte
Oi Heyman, Bom trabalho. Obrigado por compartilhar isso. Funcionará com o jQuery redimensionável também?
Haris
1

Você pode tentar usar jquery.pep.js :

jquery.pep.js é um plugin jQuery leve que transforma qualquer elemento DOM em um objeto arrastável. Ele funciona em quase todos os navegadores, do antigo ao novo, do toque ao clique. Eu o construí para atender a uma necessidade em que a capacidade de arrastar do jQuery UI não atendia, já que não funcionava em dispositivos de toque (sem algum hackery).

Site , link do GitHub

martynas
fonte
1
Obrigado @martynas, vou dar uma olhada!
artlung