Como eu fiz um controle deslizante realmente adaptável (carrossel)

Bom dia, queridos leitores e escritores!


Hoje vou contar como o projeto me encarou com a tarefa de fabricar um controle deslizante adaptável e o que veio dele


Sobre o artigo e para quem ele é


Estou escrevendo este artigo não tanto porque quero que a comunidade responda a esse problema, mas também porque a solução para as perguntas do artigo me parece fundamental para entender a adaptabilidade do slider na Web. Se alguém já escreveu esses componentes, responda e compartilhe experiências semelhantes


Um pouco sobre o que aconteceu e quais ferramentas foram usadas


Em um aplicativo React, você precisa fazer um carrossel (daqui em diante usarei esse nome), cujos elementos visualizam harmoniosamente a tela de qualquer tamanho. Existem várias limitações:


  1. A largura máxima do elemento é 150 px
  2. Ferramenta usada - Carrossel de coruja reagir
  3. O tamanho máximo do contêiner para o carrossel é 1190 px
  4. Também existem indicadores da propriedade de preenchimento para diferentes telas (afeta a largura da parte visível do contêiner) e margem (entre elementos de pelo menos 5 pixels)
  5. O carrossel deve ir em ciclos
    E outras condições que não afetam o assunto do artigo

Digressão na mecânica do carrossel


Muitos carrosséis (o React Owl Carousel não é uma exceção) usam a classe ativa especial para mostrar quais descrevem os elementos atualmente exibidos na tela.


Para exibir um loop infinito na tela, o primeiro e o último elementos são duplicados (a mecânica e os problemas dessa dublagem são um tópico para um artigo separado).


As propriedades são descritas por objetos especiais. Estaremos interessados ​​no objeto responsivo, responsável por redesignar propriedades.


O restante dos dados sobre a mecânica do trabalho será claro no decorrer da descrição da solução.


Primeiros problemas


No início, tudo correu bem - os próprios elementos foram escritos e estilizados, as propriedades básicas de todo o carrossel foram explicitadas. Problemas iniciados ao definir a propriedade {loop: true}


O carrossel está girando inadequadamente


Ao rolar para o final da lista, o espaço livre permanecia no carrossel e, por algum tempo, estava rolando nele.


O motivo foi a largura máxima do elemento, não consistente com seu número. Um exemplo concreto é a largura do contêiner 1190 px, com o número de elementos definido como 3.


Em outras palavras, o carrossel espera que 3 elementos se estendam para 1190px e eles não podem se tornar maiores que 150px.


Aumentando o número de itens


O problema assume um ângulo diferente: se houver muitos elementos por contêiner, sua largura se tornará muito pequena (e houver conteúdo dentro deles!) Se eu definir a propriedade min-width, em alguns tamanhos de tela, os elementos se arrastam um no outro, ignorando a margem, o que viola as condições .


Resumimos as condições de adaptabilidade


  1. O número de elementos na tela deve ser menor que a proporção entre o tamanho da tela e
    largura mínima do elemento - caso contrário, elementos da largura mínima não caberão na tela.
  2. A proporção do tamanho da tela para o número estimado de elementos não deve exceder o comprimento máximo estimado, caso contrário, há um problema com o loop.
  3. As condições descritas acima devem ser atendidas para qualquer tamanho de tela (de 330p a 1190px).

Resolvemos o problema como programadores


Se você abordar o problema sequencialmente, é óbvio que você deve desistir de algo, no meu caso, era a largura mínima do elemento.


Qual deve ser a largura mínima do elemento para que, para todas as telas de contêiner, as condições de adaptabilidade sejam atendidas?


//       const getBackTrace = (minScreen = 300, maxElementWidth = 150) => { let backTrace = {} for (let minElementWidth = maxElementWidth; minElementWidth > 0; minElementWidth--){ //            //     backTrace for(let screen = minScreen; screen <= 1100; screen++){ let elementCount = screen / minElementWidth | 0 if((screen / elementCount) > maxElementWidth){ backTrace[minElementWidth] = screen break } } } for(let key in backTrace){ //        ,      if (backTrace[key - 1] == undefined){ backTrace.result = key - 1 return backTrace } } } // getBackTrace(300, 150).result = 100 

O resultado em 100px não foi adequado para mim, pois não me permite ajustar todo o conteúdo do elemento. Portanto, continuamos a busca até encontrar o valor certo e procurar o que mais sacrificar.


Lembra da legenda? Para pesquisar, escreva uma função


 const getMinScreen = (minWidth = 300, maxWidth = 767, maxElementWidth = 150) => { let research = [] //  ,          // getBackTrace,       for(let min = minWidth; min < maxWidth; min++){ let { result } = getBackTrace(min, maxElementWidth) research.push({result, min}) } //          "  "  return research .reduce((acc, curr, idx, arr) => { let obj = {} let {min, result} = curr obj[min] = result if(idx == 0) return obj if(arr[idx-1].result == result){ return {...acc} } else { return {...acc, ...obj} } }, {}) } /* Returned object {300: 100, 303: 101, 306: 102, 309: 103, 312: 104, 315: 105, 318: 106, 321: 107, 324: 108, 327: 109, 330: 110, 333: 111, 336: 112, 452: 113, 456: 114, 460: 115, 464: 116, 468: 117, 472: 118, 476: 119, 480: 120}   480    */ 

Considerando o objeto obtido, você pode ver um grande salto na transição de 336px para 452px.
Tomei uma decisão decidida de limitar a adaptabilidade a 36px.


Nós descrevemos o objeto adaptativo


Parece que o problema foi resolvido, mas essa solução prova apenas que a conformidade com as condições é possível para telas de 336px, mas não descreve o método. Mas existem diferentes condições que me limitam na produção de um objeto com propriedades de adaptabilidade
Tendo aceito por mim mesmo que a largura mínima de um elemento sem perdas pode ser de 107 px, variando o valor da margem, cheguei aos seguintes indicadores:


Ecrãmargemlargura mínima
336+5107
468+10107
763+15112

A única coisa que resta é coletar os dados recebidos em uma pilha e implementar o objeto adaptável:


 getResponsiveOwlItems = () => { let responsive = {}; responsive[0] = {items: 2, nav: false} // 112 = 107 (minimal div) + 5 (margins) let itemMinWidthReference = 112; const getOneWidth = deviceWidth => deviceWidth / itemMinWidthReference | 0 // 1190 - container width for(let i = itemMinWidthReference * 3 + 20; i <= 1190; i += itemMinWidthReference){ // .container padding > 768 90px + padding 90(.container) // .container padding < 768 40px + padding -40(.container) // +20px stagePadding let padding = i > 767 ? 200 : 20 if(i > (468 + padding)) { itemMinWidthReference = 117 } if(i > (767 + padding)) { itemMinWidthReference = 127 } let items = getOneWidth(i - padding) let nav = i > 700 ? true : false let margin = 5; if (i > 468){ margin = 10 } if (i > 767){ margin = 15 } responsive[i.toString()] = {items, nav, margin} //      itemMinWidthReference i = i - (i % itemMinWidthReference) + 1 } return responsive; } 

No dia da publicação, tudo parece lógico e não pude reproduzir o erro no carrossel - tudo provavelmente funciona como planejado.


Obrigado por sua atenção, aguardando seus comentários e comentários!

Source: https://habr.com/ru/post/pt461525/


All Articles