Hola, soy Miguel y para hoy les traigo este tutorial.
Construimos una biblioteca de componentes de reacción bien definida. Esto es importante para nosotros, ya que queríamos reutilizar muchos de estos diseños y componentes con frecuencia en el futuro.
Uno de los componentes principales que construimos es el carrusel para dispositivos móviles. Este componente es importante ya que muchas secciones de nuestros sitios web tienen contenido dispuesto horizontalmente, que por supuesto no se puede procesar correctamente en dispositivos móviles.
Un carrusel nos permitiría encajar bien ese contenido en una pantalla móvil. Aquí hay un ejemplo de lo que terminamos construyendo que destaca nuestros requisitos:
Esta imagen muestra una de las aplicaciones de nuestro carrusel. Como puede ver, teníamos requisitos muy simples.
- El carrusel es solo para dispositivos móviles y debería funcionar con eventos de toque / arrastre.
- El contenido debe desplazarse libremente y no enfocar con fuerza ninguno de los contenidos.
- Los puntos deben resaltar la cantidad de contenido desplazado.
Una vez que tuvimos claros nuestros requisitos, revisamos algunos paquetes populares de NPM para el carrusel, como react-slick
, bootstrap carousel
, react-responsive-carousel
, etc.
Pero estos carruseles no permitían el desplazamiento libre y parecía un esfuerzo poco valorado modificarlos según nuestras necesidades. Además, algunos de estos paquetes estaban llenos de funciones que no necesitábamos en absoluto.
Funciones como imágenes ampliables, botones de panel, una variedad de indicadores de desplazamiento integrados, etc. terminarían volviéndose abultados para nosotros. Así que finalmente decidimos construir el carrusel nosotros mismos.
Índice
Construyendo la estructura de componentes
Queríamos mantener el consumo del componente lo más simple posible. Nuestro requisito era que simplemente envolviendo <Carousel />
alrededor de algún contenido debería ser suficiente para representar el carrusel.
Lo que significaba que nuestro componente tenía que envolver el children
elementos con CSS adecuado y tuvo que manejar la representación de indicadores de desplazamiento.
Teniendo esto en cuenta, decidimos envolver los elementos secundarios dentro <CarouselContainer/>
y usa un componente separado <ScrollIndicator/>
para renderizar los puntos de desplazamiento. Así que esto es lo que terminamos con:
import ScrollIndicator from './ScrollIndicator'; import { CarouselContainer, MainContainer } from './styled'; const Carousel = props => { const target = React.createRef(); const { count, children } = props; return ( <MainContainer> <CarouselContainer ref={target}> {children} </CarouselContainer> <ScrollIndicator count={count} target={target}/> </MainContainer> ) } export default Carousel;
<CarouselContainer/>
y <MainContainer/>
son solo elementos div con CSS aplicado a ellos usando componentes-estilizados.
El <CarouselContainer/>
se supone que es un contenedor de los elementos del carrusel. Lo que significa que debe satisfacer tres condiciones principales:
- Debería representar sus elementos secundarios horizontalmente.
- No debería mostrar la barra de desplazamiento.
- Debe tener una pista de la cantidad de desplazamiento.
Los puntos 1
y 2
son bastante sencillos con el uso de CSS. Usamos flex para renderizar los elementos horizontalmente con un ancho fijo y desbordamiento automático para obtener la experiencia de desplazamiento.
Entonces, el CSS final de <CarouselContainer/>
se convierte en:
const CarouselContainer = styled.div` display: flex; flex-direction: row; width: 100%; overflow-x: auto; ::-webkit-scrollbar { display: none; } `;
A tener en cuenta: Nosotros usamos
::webkit-scrollbar
propiedad para ocultar la barra de desplazamiento, que es no compatible con firefox e IE (árbitro), por lo que si la compatibilidad del navegador es importante para usted, esta no es la mejor manera.
Hasta ahora, esta es solo una lista horizontal sin una barra de desplazamiento. Esta es técnicamente la funcionalidad que necesitamos, pero no será un carrusel sin el indicador de desplazamiento.
El indicador de desplazamiento
Ahora, llegando al bit de seguimiento de desplazamiento del carrusel, asignamos una referencia al <CarouselContainer/>
utilizando el gancho createRef()
.
Esta referencia luego se pasa como un accesorio llamado objetivo al <ScrollIndicator/>
componente que contiene la lógica principal para mostrar los puntos indicadores de desplazamiento.
Target
se usaría para calcular scrollProgress
usando las propiedades de desplazamiento DOM (se explica mejor a través del código). Leer más sobre react ref aquí.
Para empezar, así es como se ve la declaración de devolución final para el componente <ScrollIndicator/>
:
return ( <ScrollIndicatorContainer> {renderDots()} </ScrollIndicatorContainer> );
<ScrollIndicatorContainer/>
de nuevo es solo un div con estilo que centra los puntos de desplazamiento y los alinea horizontalmente.
RenderDots()
renderiza los puntos activos / inactivos
.
La idea aquí es crear un oyente que escuche los eventos de desplazamiento / toque
y calcule el progreso del desplazamiento que luego se puede usar para representar los puntos. Salvamos el scrollProgress
en el estado local:
const [scrollProgress, setScrollProgress] = useState(0);
Y el oyente que calcula el progreso del desplazamiento:
const scrollListener = () => { if (!target.current) { return; } const element = target.current; const windowScroll = element.scrollLeft; // Distance of the scrollbar from the leftmost point const totalWidth = element.scrollWidth - element.clientWidth; // Total width the scrollbar can traverse if (windowScroll === 0) { return setScrollProgress(0); } if (windowScroll > totalWidth) { return setScrollProgress(100); } setScrollProgress((windowScroll / totalWidth) * 100); }
Target
es la referencia que creamos para<CarouselContainer />
al principio usando el hookcreateRef
. Usamos esto para obtener las propiedades del elemento necesarias para calcular el estado del desplazamiento.Const windowScroll = element.scrollLeft;
. Esta propiedad nos da la posición de la barra de desplazamiento horizontal desde el punto más a la izquierda del contenedor.Const totalWidth = element.scrollWidth — element.clientWidth;
. Esto nos da el ancho total del contenedor al que puede desplazarse la barra de desplazamiento.
Finalmente con estos tres valores, podemos calcular el progreso del scroll en porcentaje y configurarlo en el estado:
setScrollProgress((windowScroll / totalWidth) * 100);
A tener en cuenta: Para barras de desplazamiento verticales, reemplace
scrollLeft
,scrollWidth
yclientWidth
conscrollTop
,scrollHeight
yclientHeight
.
¿Cuándo activamos el cálculo?
Nuestra función para calcular el progreso del desplazamiento está lista, pero aún necesitamos activarla repetidamente para seguir actualizando el progreso del desplazamiento.
Usamos el useEffect
hook
para vincular esta función con un detector de eventos. Para nuestro caso de uso, esto era solo para dispositivos móviles, por lo que lo vinculamos con el touchmove
event
, pero también podemos vincularlo con eventos de desplazamiento para el uso del escritorio.
useEffect(() => { target.current.addEventListener('touchmove', scrollListener); return () => target.current && target.current.removeEventListener('touchmove', scrollListener); });
Este enlace asegurará que cada vez que el usuario toque y arrastre el <CarouselContainer/>
y scrollListener()
actualizará el estado de desplazamiento para nuestro uso.
Ahora la parte más fácil.
Renderizando los puntos
Esta parte dependería de lo que quieras mostrar como indicador de desplazamiento. Para nosotros, es un punto con un utilería para resaltarlo.
const renderDots = () => { const selectedDotValue = (scrollProgress * count) / 100; return [ ...Array(count).keys() ].map( index => ( <Dot key={index} active={selectedDotValue >= index && selectedDotValue <= index + 1}/> )); }
El componente <Dot/>
es exactamente lo que parece, representa un punto (es un elemento <div/>
HTML con color de fondo y radio de borde). El accesorio activo decide su color, pero eso es todo.
Usamos el accesorio de conteo aquí para decidir el número de puntos. El descanso es solo un poco de matemáticas para decidir qué punto debe resaltarse.
¡Eso es! El carrusel está listo. Hoy utilizamos este componente en varios lugares para nuestras páginas web móviles.
Podemos agregar controles deslizantes, botones de panel, etc. con nuestras opciones de diseño. Al final, creímos que los pros superaron a los contras y estamos muy contentos con los resultados finales.
Si encuentra algún problema en los fragmentos de código anteriores, no dude en comentar.
Añadir comentario