Crie um Swiper de Imagem Snapping como o Instagram com React

Jason Brown Blocked Unblock Seguir Seguindo 6 de janeiro

Instagram tem uma experiência de imagem muito legal. À medida que você rola por cima de um conjunto de imagens, ele se move para a esquerda / direita e, em seguida, se encaixa em qualquer imagem que tenha sido parcialmente ajustada.

Parece um pouco algo assim. Nós vamos resolver fazer uma versão disso.

Obter algumas imagens

Unsplash é o lugar para se estar quando se trata de obter belas imagens gratuitas.

Se você quiser acessar os que eu escolhi, você pode pegá-los da pasta github do repo aqui: Our Images

Eu fui para imagens que eram aproximadamente as mesmas dimensões, então quando chegou a hora de renderizá-las, nós poderíamos usar uma largura singular. este

Render-los lado a lado

Vamos mergulhar no esquema básico do nosso aplicativo. Definimos largura / altura na frente, no entanto, isso pode ser desviado de um tamanho de contêiner dinâmico no futuro. Para simplificar o conceito, vamos nos concentrar nas dimensões estáticas.

Precisamos construir nossa estrutura DOM de tal maneira que o nosso contêiner externo seja como uma janela para o nosso contêiner interno.

Nosso contêiner interno é aquele que será rolado e conterá todas as nossas imagens. Em seguida, usamos o contêiner externo para criar uma janela de 700x400 no recipiente interno ao qual nos referiremos como o swiper .

Para realizar essa janela no swiper, nosso wrapper main precisa ser configurado para overflow: 'hidden' . Então, nossas dimensões de estilo que definimos criarão a janela para a visualização. Nosso swiper será um contêiner de flexão que terá o overflow-x definido como visível. Ele vai automaticamente colocar as nossas imagens em uma fileira.

Por fim, configuramos nossas animações futuras dizendo que nossa propriedade de transição será o estilo de transformação e, em seguida, forneceremos ao navegador algumas dicas sobre o que vai mudar para otimizar nossa animação / movimento.

O object-fit é para nossas imagens, isso irá contê-las para que elas mantenham sua proporção ao mesmo tempo em que 700x400 para caber dentro da nossa janela de 700x400 .

Obter rolagem

No nosso container main , aplicamos o evento onWheel . Isso nos permite capturar qualquer evento de roda / rolagem quando o mouse estiver sobre a nossa div . Portanto, mesmo que não haja nada para rolar e nenhuma barra de rolagem, ainda podemos capturar eventos de rolagem.

Para salvar o movimento atual da nossa rolagem, adicionamos um novo bit ao estado e o definimos como 0 . Isto irá rastrear o nosso offset e a partir de 0 nós estamos dizendo "inicie no início do container rolável".

Queremos suportar mais de rolagem, queremos apoiar os movimentos de toque. Então, precisaremos unificar tudo em uma função singular. Nós só precisamos do deltaX também conhecido como a mudança horizontal para aquele evento em particular.

O deltaX pode ser positivo ou negativo dependendo de qual direção o usuário está rolando. Este deltaX geralmente será um pequeno número.

Precisamos fazer referência ao estado anterior, então precisamos usar um estilo de referência de retorno de chamada setState . Primeiro, calculamos alguns dados.

O primeiro é o comprimento total das imagens que temos, depois criamos o nosso nextMovement que é a próxima posição para compensar o nosso swiper .

Precisamos configurar algumas restrições para que, à medida que você rola para a esquerda e / ou alcance o final, você não vá até o fim e pare quando chegar às extremidades. Para fazer isso, verificamos se nosso nextMovement futuro é menor que 0 , se formos configurados como 0 .

Então, se o nextMovement for maior que o número total de nossas imagens multiplicado pela largura da imagem. Se é mais do que nós definimos para o máximo.

Finalmente, aplicamos nosso movement ao nosso para o nosso swiper. Precisamos multiplicar por -1 para que o movement esquerda / direita funcione com o translateX e mova as coisas para a esquerda / direita.

Tocar

Para trabalhar em dispositivos móveis, precisamos lidar com os toques. Precisamos lidar com os eventos start, move e end dos toques.

Não podemos simplesmente obter o delta de um toque na Web, por isso precisamos acompanhar nossa última posição de toque.

Após o início do toque, economizamos onde o primeiro toque do dedo estava localizado.

Então calculamos o delta do movimento X. Podemos subtrair a localização atual do toque para onde o nosso toque anterior estava. Assim que tivermos o delta, podemos atualizar nosso lastTouch com o toque atual.

Finalmente, podemos chamar nosso handleMovement com nosso delta e, quando o toque estiver concluído, poderemos limpar o nosso toque anterior para 0 .

Seguindo em frente

À medida que movemos o controle deslizante para a frente, precisaremos detectar em quais imagens aterrissamos para que possamos normalizar nosso slide e encaixar em uma imagem específica. Para nossa roda, precisamos modificar o handleWheel . Economizamos um tempo limite para wheelTimeout e o wheelTimeout em cada evento. À medida que o usuário rola e, eventualmente, pára, os eventos param de fluir. Nós nos damos 100ms antes de tentarmos encaixar a imagem em um índice específico.

Para os eventos de toque, tudo o que precisamos fazer é chamar diretamente a nossa função de movimento final.

Precisamos adicionar o currentIndex porque sem saber onde começamos, não poderemos saber em qual direção o usuário realmente se mudou.

Para que tudo funcione, precisamos fazer alguns cálculos. A primeira é obter a posição final do movement e dividi-la pela largura total da imagem. Isso nos dará a imagem e a porcentagem de qualquer outra imagem que estamos vendo.

Por exemplo, se rolarmos a metade da primeira imagem, esse número seria .5 , ou se você rolou completamente além da primeira imagem e um pouco na terceira imagem, esse número seria algo como 1.2 .

Para obter a parte parcial de uma imagem, usamos o modulus que, quando dividido pelo número do processo, retornará o restante. Se dividirmos por 1 como fazemos aqui, isso sempre nos dará o resto, também conhecido como casa decimal. No nosso caso do exemplo anterior, isso retornaria .5 ou .2 .

Em seguida, obtemos nosso endingIndex final, que é o número total de imagens que ignoramos. Portanto, no caso do .5 , não ignoramos nenhuma imagem, então estamos no 0 . À medida que endingIndex 1 imagem completa, o endingIndex seria 1.

Finalmente, calculamos o delta. O deltaInteger é como vamos detectar se a direção do nosso movimento. Se começarmos em um índice de 0 e terminar em 1 então movemos uma imagem completa para frente.

Mas se começamos na segunda imagem (também conhecida como currentIndex: 1 ), então, rolar para trás, nosso endingIndex é 0 . Então nosso delta agora é -1 .

Vamos começar com a suposição ingênua de que nextIndex é o número total de imagens que o usuário percorreu.

No futuro, queremos que os botões se movam para trás / para frente, para que novamente consolidemos nossa lógica de movimento / transição em uma função singular chamada transitionTo . Nós salvamos o currentIndex , então também calculamos o offset que precisamos mover em direção ao qual é o índice multiplicado pela largura da imagem.

Agora precisamos fazer alguma lógica. Assumindo que o nosso endingIndex é quantas imagens nós passamos, se rolássemos para 1.9 isso seria ignorar toda a primeira imagem e 90% da segunda imagem.

Está claro que o usuário agora está olhando para a terceira imagem. Sem mais lógica, iríamos retroceder e veríamos a segunda imagem.

Primeiro, verificamos se estamos avançando, ou seja, se o nosso deltaInteger é positivo ou 0 . Então, precisamos verificar quanto de qualquer outra imagem estamos vendo.

O Instagram é muito agressivo ao mover um usuário para a próxima imagem, por isso, se estivermos olhando para outra imagem, pelo menos 10% , queremos encaixar nessa foto. Então, no nosso caso, se adicionarmos 1 ao nosso nextIndex .

Mover-se para Trás

Retroceder é como avançar, mas nossa porcentagem da imagem que estamos vendo será .9 uma vez que estaremos olhando para o lado direito da imagem.

Então, se o nosso deltaInteger for negativo, definimos nosso nextIndex para o índice atual menos o número de imagens que movemos. Isso nos dará a próxima imagem, mesmo se estamos apenas olhando para uma pequena parte dela.

Precisamos fazer o mesmo que antes, mas de forma ligeiramente diferente. Verificamos se a parcial está olhando para mais de 90% da imagem. Se estiver a 95% apenas uma pequena faixa ficará visível, por isso adicionamos 1 e, assim, voltamos para a foto mais visível para o usuário.

Transições

Agora, para fazer a transição de uma posição atual para outra, precisamos definir uma duração de transição. A duração é padronizada como 0 então rolamos as coisas instantaneamente. Se aplicarmos uma duração e uma nova posição de movimento ao mesmo tempo, as coisas serão animadas e encaixadas.

Em seguida, configuramos um tempo limite para limpar a duração quando chegamos ao fim. Nós podemos detectar quando a animação termina e matar o estado, mas existe a possibilidade de um usuário interromper nosso snap. Então, precisamos lidar com isso em nossas outras funções. Nós convertemos nosso decimal em uma quantidade de milissegundos multiplicando por 100 . Então .5s seria equivalente a 500ms .

No final do nosso handleMovementEnd nós handleMovementEnd o valor mínimo e passamos isso para a nossa duração. Temos um máximo de .5s mas .5s calcular quanto da imagem é totalmente visível e tornar a animação mais rápida se apenas um pequeno bit estiver visível.

Para finalizar o snap, se o usuário interromper a animação, limpamos o tempo limite da transição e, para o próximo movimento, definimos a duração para 0s então voltamos ao movimento instantâneo.

Finalmente, precisamos aplicar nosso transitionDuration ao nosso swiper .

Botões anteriores / próximos

O último bit de código está adicionando nossos próximos / anteriores botões, bem como escondendo-os adequadamente.

Nós retiramos e determinamos algumas variáveis como o número total de imagens que temos e o movimento máximo que podemos traduzir o swiper.

Para o movimento de back , se estamos atualmente em 0 , estamos no início do contêiner. Isso significa que não queremos que o botão voltar apareça, então o ocultamos. Como tudo isso está sendo atualizado ao vivo e instantaneamente, é um bom valor determinar a visibilidade de nossos botões.

Quando clicado, o botão nos moverá para o nosso currentIndex - 1 por meio segundo.

O mesmo conceito vale para o nosso próximo botão, mas só o processaremos se o container não tiver sido rolado para o seu valor máximo. Então, se clicado, passamos para o currentIndex + 1 por meio segundo.

Fazemos uma única classe de move para o nosso botão e usamos a técnica de posicionamento vertical, definindo o top: 50% e depois traduzimos de volta para cima -50% . É também por isso que precisamos que o nosso wrap de classe main seja relative .

Então nós eliminamos nossas classes separadas para posicioná-las à left/right da borda.

Final

Foram realizadas! Agora temos um carrossel de imagens rolável e deslizável. Confira o código aqui https://github.com/codedailyio/teach/tree/instagramSwiper

Obtenha mais conteúdo assim no Code Daily